Java内存泄漏发生的情况

时间:2021-03-10 20:58:20

转自:http://www.jianshu.com/p/93b91ea18c28

虽然Java自带垃圾回收机制(GC),程序员不需要手动进行内存管理,但是仍然会出现内存泄漏的情况。尽管如此,Java的自动内存管理,比起C/C++,内存泄漏的情况大大减少了。下面总结下什么情况下会发生Java内存泄漏。

静态集合类

在使用Set、Vector、HashMap等集合类的时候需要特别注意,有可能会发生内存泄漏。当这些集合被定义成静态的时候,由于它们的生命周期跟应用程序一样长,这时候,就有可能会发生内存泄漏,看下面代码:

[java] view plain copy print?Java内存泄漏发生的情况Java内存泄漏发生的情况
   
  
  
  1. class StaticTest  
  2. {  
  3.     private static Vector v = new Vector(10);  
  4.   
  5.     public void init()  
  6.     {  
  7.         for (int i = 1; i < 100; i++)  
  8.         {  
  9.             Object object = new Object();  
  10.             v.add(object);  
  11.             object = null;  
  12.         }  
  13.     }  
  14. }  
Java内存泄漏发生的情况

在上面的代码中,循环申请了Object对象,并添加到Vector中,然后将对象设置为null,可是这些对象因为被Vector引用着,因此并不能被GC回收,因此造成了内存泄漏。因此,要释放这些对象,还需要被它们从Vector删除,最简单的方法就是将Vector设置为null

集合里的对象属性值被改变

看以下代码,(在下面代码中,Student类型必须重写equals和hashcode方法,如果不重写方法,仍然是可以删除的,Student类见文章最后)

之前有个面试题,问Set中的对象可不可以修改,现在看来,如果修改了,可能会导致hashcode的改变,从而导致Set的remove失效,从而出现内存泄露的情况,那如果Set在使用完之后赋值为null是不是就可以消除引用了?

[java] view plain copyprint?Java内存泄漏发生的情况Java内存泄漏发生的情况
  1. public static void main(String[] args)  
  2. {  
  3.     Set<Student> set = new HashSet<Student>();  
  4.     Student s1 = new Student("Jack");  
  5.     Student s2 = new Student("Mary");  
  6.     Student s3 = new Student("Eason");  
  7.   
  8.     set.add(s1);  
  9.     set.add(s2);  
  10.     set.add(s3);  
  11.   
  12.     System.out.println(set.size());//3  
  13.     s2.setName("Jackson"); //修改属性,此时s2元素对应的hashcode值发生改变  
  14.     set.remove(s2);        // remove不掉,造成内存泄漏  
  15.     set.add(s2);           // 添加成功  
  16.   
  17.     System.out.println(set.size());//4  
  18. }  
Java内存泄漏发生的情况

在这个例子中,由于对象s2的属性值被改变了,因此不能从set中删除,所以set中会一直保持着s2的引用,不能被回收,造成了内存泄漏。

监听器

在Java中,我们经常会使用到监听器,如对某个控件添加单击监听器addOnClickListener(),但往往释放对象的时候会忘记删除监听器,这就有可能造成内存泄漏。好的方法就是,在释放对象的时候,应该记住释放所有监听器,这就能避免了因为监听器而导致的内存泄漏。

各种连接

Java中的连接包括数据库连接、网络连接和io连接,如果没有显式调用其close()方法,是不会自动关闭的,这些连接就不能被GC回收而导致内存泄漏。一般情况下,在try代码块里创建连接,在finally里释放连接,就能够避免此类内存泄漏。

外部模块的引用

调用外部模块的时候,也应该注意防止内存泄漏。如模块A调用了外部模块B的一个方法,如:
public void register(Object o)
这个方法有可能就使得A模块持有传入对象的引用,这时候需要查看B模块是否提供了去除引用的方法,如unregister()。这种情况容易忽略,而且发生了内存泄漏的话,比较难察觉,应该在编写代码过程中就应该注意此类问题。

单例模式

使用单例模式的时候也有可能导致内存泄漏。因为单例对象初始化后将在JVM的整个生命周期内存在,如果它持有一个外部对象(生命周期比较短)的引用,那么这个外部对象就不能被回收,而导致内存泄漏。如果这个外部对象还持有其它对象的引用,那么内存泄漏会更严重,因此需要特别注意此类情况。这种情况就需要考虑下单例模式的设计会不会有问题,应该怎样保证不会产生内存泄漏问题。



文/zhutoulwz(简书作者)
原文链接:http://www.jianshu.com/p/93b91ea18c28
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

[java] view plain copyprint?Java内存泄漏发生的情况Java内存泄漏发生的情况
  1. public class Student {  
  2.     String name;  
  3.       
  4.     public Student(String name){  
  5.         this.name = name;  
  6.     }  
  7.   
  8.     public String getName() {  
  9.         return name;  
  10.     }  
  11.   
  12.     public void setName(String name) {  
  13.         this.name = name;  
  14.     }  
  15.   
  16.     @Override  
  17.     public int hashCode() {  
  18.         final int prime = 31;  
  19.         int result = 1;  
  20.         result = prime * result + ((name == null) ? 0 : name.hashCode());  
  21.         return result;  
  22.     }  
  23.   
  24.     @Override  
  25.     public boolean equals(Object obj) {  
  26.         if (this == obj)  
  27.             return true;  
  28.         if (obj == null)  
  29.             return false;  
  30.         if (getClass() != obj.getClass())  
  31.             return false;  
  32.         Student other = (Student) obj;  
  33.         if (name == null) {  
  34.             if (other.name != null)  
  35.                 return false;  
  36.         } else if (!name.equals(other.name))  
  37.             return false;  
  38.         return true;  
  39.     }  
  40. }  
Java内存泄漏发生的情况





   
  
  
0
0
   

我的同类文章

http://blog.csdn.net 更多文章