Java中七个潜在的内存错误,你知道几个?

如果GC无法回收内存中不再使用的对象,则定义为内存有泄露

 未关闭的资源类

当我们在程序中打开一个新的流或者是新建一个网络连接的时候,JVM都会为这些资源类分配内存做缓存,常见的资源类有网络连接,数据库连接以及IO流。值得注意的是,如果在业务处理中异常,则有可能导致程序不能执行关闭资源类的代码,因此最好按照下面的做法处理资源类


  1. public void handleResource() { 
  2.     try { 
  3.         // open connection 
  4.         // handle business 
  5.     } catch (Throwable t) { 
  6.         // log stack 
  7.     } finally { 
  8.         // close connection 
  9.     } 

 未正确实现equals()和hashCode()

假如有下面的这个类


  1. public class Person { 
  2.     public String name
  3.      
  4.     public Person(String name) { 
  5.         this.name = name
  6.     } 

并且如果在程序中有下面的操作


  1. @Test 
  2. public void givenMapWhenEqualsAndHashCodeNotOverriddenThenMemoryLeak() { 
  3.     Map<Person, Integer> map = new HashMap<>(); 
  4.     for(int i=0; i<100; i++) { 
  5.         map.put(new Person("jon"), 1); 
  6.     } 
  7.     Assert.assertFalse(map.size() == 1); 

可以预见,这个单元测试并不能通过,原因是Person类没有实现equals方法,因此使用Object的equals方法,直接比较实体对象的地址,所以map.size() == 100

如果我们改写Person类的代码如下所示:


  1. public class Person { 
  2.     public String name
  3.      
  4.     public Person(String name) { 
  5.         this.name = name
  6.     } 
  7.      
  8.     @Override 
  9.     public boolean equals(Object o) { 
  10.         if (o == this) return true
  11.         if (!(o instanceof Person)) { 
  12.             return false
  13.         } 
  14.         Person person = (Person) o; 
  15.         return person.name.equals(name); 
  16.     } 
  17.      
  18.     @Override 
  19.     public int hashCode() { 
  20.         int result = 17; 
  21.         result = 31 * result + name.hashCode(); 
  22.         return result; 
  23.     } 

则上文中的单元测试就可以顺利通过了,需要注意的是这个场景比较隐蔽,一定要在平时的代码中注意。

非静态内部类

要知道,所有的非静态类别类都持有外部类的引用,因此某些情况如果引用内部类可能延长外部类的生命周期,甚至持续到进程结束都不能回收外部类的空间,这类内存溢出一般在Android程序中比较多,只要MyAsyncTask处于运行状态MainActivity的内存就释放不了,很多时候安卓开发者这样做只是为了在内部类中拿到外部类的属性,殊不知,此时内存已经泄露了。

【声明】:芜湖站长网内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。

相关文章