java垃圾回收机制
java中,垃圾回收(GC,Garbage Collection)是对程序中不再使用的内存就进行回收。
- 什么是不再使用的内存?
public class testGC {
public static void main(String[] args) {
Integer i1 = new Integer(1);
Integer i2 = new Integer(2);
i2 = i1;
}
}
在这一段代码中,计算机会分别给对象i1、i2分配内存,对于GC来说,它是使用有向图来记录和管理堆内存中的所有对象的,那么在执行
Integer i1 = new Integer(1);
Integer i2 = new Integer(2);
的时候,内存分配的有向图是这样的:
当计算机执行到
i2 = i1;
它的资源有向图变成这样:
此时资源2所占的内存是不可达的,即为不再使用的内存
因此,java语言中的垃圾回收机制:
当一个对象不被使用的时候,GC会将该对象标记为垃圾,并在后面一个不确定的世界进行回收。注意,并不是立即回收,程序员无法控制其进行回收的时间,虽然开发人员可以通过system.gc()方法来通知垃圾回收器运行,但是JVM并不能保证垃圾回收器马上就能运行。由于gc方法的执行会停止所有的响应,去检查内存中是否有可回收的对象,这会对程序的正常运行以及性能造成极大威胁,所以在实际编程中并不推荐频繁使用gc方法。
分代垃圾回收
提到对象,不得不提及堆。垃圾回收器对多余的对象空间进行回收的过程其实就是对堆的管理过程,目前最常用的JVM采用的算法是分代回收。
- 分代回收
根据对象的生命周期的长短把对象分成不同的种类,并进行内存回收
分代回收将JAVA堆分为三代,分别为年轻代、老年代和持久代
- 年轻代
年轻代又被分为3个部分,一个Eden区和两个相同的Survivor区。
Eden区是用来存储新建的对象的
Survivor区是大小相同的两个区域,作为双缓存起内存管理作用,两个Survior区必须得始终保持一个是空的
- 老年代
重要存储生命周期较长的对象、超大的对象(无法在年轻代分配的)
- 永久代
存放代码、字符串常量池和静态变量等可以持久化的数据
内存分配的过程:
1.新建的对象优先在年轻代的Eden区分配内存,如果Eden区的内存已满,在创建对象的时候,会因为无法申请到空间而触发minorGc操作,此操作主要是用来对年轻代进行垃圾回收:把Eden区中不能被回收的对象放入到空的Survivor区,而另一个Survivor区里不能被垃圾回收器回收的对象也会被放入到这个区。
2.如果在这个过程中发现这个Survivor区满了,就会把这些对象复制到老年代,或者Survivor区并没有满,但是有些对象已经存在非常长的时间了,那么它也会将这些对象复制到老年代中。
3.如果老年代也满了,会触发fullGC,fullGC是用来清理整个堆空间的,会造成很大的系统开销,因此要尽量避免fullGC操作
fullGC产生的原因以及避免的方法:
1.调用system.gc()方法
因此应该尽力避免调用此方法
2.老年代空间不足。
因此我们应该尽力做到让对象在Minor GC阶段被回收,不要创建过大的对象及数组。还有一种避免的方式:根据实际情况增大Survivor区、老年代空间或调低触发并发GC的概率。
3.持久代满。
持久代主要存放class相关的信息,当代码加载足够多类的时候就会导致持久代溢出。因此避免的方式可以是增大持久代的空间,也可以开启CMS回收持久代选项。CMS利用和应用程序线程并发的垃圾回收线程来进行垃圾回收操作