Java内存泄漏相关

 

以前学习了javaGC的原理机制,有了必定的了解,如今作一个整理总结,便于理解记忆,包括三个问题:html

1. java GC是何时作的?java

2. java GC做用的东西是什么?程序员

3. java GC具体都作了些什么事情?算法

关于java GC原理参看另外一篇随笔:数据库

http://www.cnblogs.com/clarke157/p/7091990.html编程

 

1. java GC是何时作的?网络

也就是GC的触发条件,eden 满了minor gc,升到老年代的对象大于老年代剩余空间full gc,或者小于时被HandlePromotionFailure参数强制full gc;gc与非gc时间耗时超过了GCTimeRatio的限制引起OOM,调优诸如经过NewRatio控制新生代老年代比例,经过 MaxTenuringThreshold控制进入老年前生存次数等。jvm

2. java GC做用的东西是什么?socket

从GC root搜索不到,并且通过第一次标记、清理后,仍然没有复活的对象。学习

3. java GC具体都作了些什么事情?

年轻代作的是复制清理、from survivor、to survivor是干啥用的、年老代作的是标记清理、标记清理后碎片要不要整理、复制清理和标记清理有有什么优劣势

年轻代上的内存分配是这样的,年轻代能够分为3个区域:Eden区和两个存活区(Survivor 0 、Survivor 1)。

 

  1. 绝大多数刚建立的对象会被分配在Eden区,其中的大多数对象很快就会消亡。Eden区是连续的内存空间,所以在其上分配内存极快;

  2. 当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的);

  3. 此后,每次Eden区满了,就执行一次Minor GC,并将剩余的对象都添加到Survivor0;

  4. 当Survivor0也满的时候,将其中仍然活着的对象直接复制到Survivor1,之后Eden区执行Minor GC后,就将剩余的对象添加Survivor1(此时,Survivor0是空白的)。

  5. 当两个存活区切换了几回(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代)以后,仍然存活的对象(其实只有一小部分,好比,咱们本身定义的对象),将被复制到老年代。

Java 也是有内存泄露的,虽然Java有著名的GC( 垃圾回收机制),因为Java是经过程序来分配内存空间,释放则交给GC, 因为程序编写不当,仍然会引发内存泄露。

Java中的内存泄露的状况:长生命周期的对象持有短生命周期对象的引用就极可能发生内存泄露,尽管短生命周期对象已经再也不须要,可是由于长生命周 期对象持有它的引用而致使不能被回收,这就是java中内存泄露的发生场景。例如在Application中保存一个对象,这个对象其实没有使用了,可是 因为一直被引用,形成不能回收。
内存泄露的状况是:一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即便那个外部类实例对象再也不被使用,但因为内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收。
内存泄露的另一种状况:当一个对象被存储进HashSet集合中之后,就不能修改这个对象中的那些参与计算哈希值的字段了,不然,对象修改后的哈希值与 最初存储进HashSet集合中时的哈希值就不一样了,这也会致使没法从HashSet集合中单独删除当前对象,形成内存泄露。

 

Java内存泄露根本缘由是什么呢?长生命周期的对象持有短生命周期对象的引用就极可能发生内存泄露,尽管短生命周期对象已经再也不须要,可是由于长生命周期对象持有它的引用而致使不能被回收,这就是java中内存泄露的发生场景。具体主要有以下几大类: 
一、静态集合类引发内存泄露: 
像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的全部的对象Object也不能被释放,由于他们也将一直被Vector等引用着。 
例: 
Static Vector v = new Vector(10); 
for (int i = 1; i<100; i++) 
{ 
Object o = new Object(); 
v.add(o); 
o = null; 
}// 
在这个例子中,循环申请Object 对象,并将所申请的对象放入一个Vector 中,若是仅仅释放引用自己(o=null),那么Vector 仍然引用该对象,因此这个对象对GC 来讲是不可回收的。所以,若是对象加入到Vector 后,还必须从Vector 中删除,最简单的方法就是将Vector对象设置为null。
二、当集合里面的对象属性被修改后,再调用remove()方法时不起做用。
例: 
public static void main(String[] args) 
{ 
Set<Person> set = new HashSet<Person>(); 
Person p1 = new Person("唐僧","pwd1",25); 
Person p2 = new Person("孙悟空","pwd2",26); 
Person p3 = new Person("猪八戒","pwd3",27); 
set.add(p1); 
set.add(p2); 
set.add(p3); 
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:3 个元素! 
p3.setAge(2); //修改p3的年龄,此时p3元素对应的hashcode值发生改变 

set.remove(p3); //此时remove不掉,形成内存泄漏
set.add(p3); //从新添加,竟然添加成功 
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素! 
for (Person person : set) 
{ 
System.out.println(person); 
} 
}
三、监听器 
在java 编程中,咱们都须要和监听器打交道,一般一个应用当中会用到不少监听器,咱们会调用一个控件的诸如addXXXListener()等方法来增长监听器,但每每在释放对象的时候却没有记住去删除这些监听器,从而增长了内存泄漏的机会。
四、各类链接 
好比数据库链接(dataSourse.getConnection()),网络链接(socket)和io链接,除非其显式的调用了其close()方法将其链接关闭,不然是不会自动被GC 回收的。对于Resultset 和Statement 对象能够不进行显式回收,但Connection 必定要显式回收,由于Connection 在任什么时候候都没法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会当即为NULL。可是若是使用链接池,状况就不同了,除了要显式地关闭链接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另一个也会关闭),不然就会形成大量的Statement 对象没法释放,从而引发内存泄漏。这种状况下通常都会在try里面去的链接,在finally里面释放链接。
五、内部类和外部模块等的引用 
内部类的引用是比较容易遗忘的一种,并且一旦没释放可能致使一系列的后继类对象没有释放。此外程序员还要当心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如: 
public void registerMsg(Object b); 
这种调用就要很是当心了,传入了一个对象,极可能模块B就保持了对该对象的引用,这时候就须要注意模块B 是否提供相应的操做去除引用。
六、单例模式 
不正确使用单例模式是引发内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),若是单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,致使内存泄露,考虑下面的例子: 
class A{ 
public A(){ 
B.getInstance().setA(this); 
} 
.... 
} 
//B类采用单例模式 
class B{ 
private A a; 
private static B instance=new B(); 
public B(){} 
public static B getInstance(){ 
return instance; 
} 
public void setA(A a){ 
this.a=a; 
} 
//getter... 
} 
显然B采用singleton模式,它持有一个A对象的引用,而这个A类的对象将不能被回收。想象下若是A是个比较复杂的对象或者集合类型会发生什么状况
对象A和B互相引用,最后会不会被GC回收?GC里边在JVM当中是使用的ROOT算法,ROOT算法,什么称做为ROOT呢,就是说类的静态成员,静态成员就是static修饰的那种,是“根”的 一个,根还包括方法中的成员变量,只有成员或对象不挂在根上,GC的时候就可能把他们搞掉,这里提到的循环引用,就看这个循环引用是否挂在根上,若是挂在 根上,若是这个根还被JVM的Java代码所执行的话,就不会GC掉,若是说这个根已经被释放掉了,这个对象不挂在跟上了,那个这个对象就会被GC掉。参考连接:https://www.cnblogs.com/clarke157/p/7903660.html
相关文章
相关标签/搜索