JAVA的垃圾回收机制(GC)

什么是垃圾回收?

JVM有专门的垃圾回收器负责Java的内存管理,称为GC(Garbage Collector)。负责分配内存、确保被引用的对象留在内存、回收不再被引用的对象,自动释放内存。

哪些内存需要回收?何时?怎么回收?(What?When?How?)

运行时数据区的程序计数器、虚拟机栈、本地方法栈都随线程的产生而产生、消灭而消灭。每一个栈帧分配多少内存编译时可知,因此这些区域不需要回收。而Java堆和方法区则不一样:类需要的内存不一样,创建哪些对象也要运行期才知道,因此这部分内存是动态的,需要垃圾收集器回收。在堆中,尤其新生代,一次垃圾回收可以回收70%-95%的空间,而方法区的效率远低于此。

如何判断对象是否存活?

最简单的是对象添加引用计数器,为0时则对象不再存活。此方法最主要的问题无法解决对象间的循环引用。
因此Java虚拟机没有使用此方法,而是使用"可达性分析算法":
当一个对象到GC Roots没有引用链相连的话,可以回收。
可以作为GC Roots的对象有:
虚拟机栈中引用的对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI引用的对象。

垃圾回收有几种算法?

标记-清除算法

先标记要回收的对象,标记完成后统一清除回收。
效率不高,并且会产生内存碎片。

复制算法

将内存分两块,当一块用完了,就把存活的对象拷贝到另一块中,用完的那块一次清理掉。
最典型的应用是对新生代的回收,新生代的对象98%都是“朝生夕死”的,商业虚拟机都采用这种方法回收新生代。新生代的内存分为一个Eden区和两个Survivor区(比例是8:1:1)。回收时,将Eden和Survivor区存活的对象复制到另一个Survivor区中,然后清理掉Eden区和Survivor区。前面说过,新生代的存活时间短,所以当垃圾回收时,可以回收掉90%的内存,存活的对象放入10%的Survivor中,所以比例8:1:1可以满足要求。
如果Survivor区中不够存放,那么需要依赖其他内存(老年代)进行分配担保,进入老年代。

标记-整理算法

复制算法不适用于老年代,老年代使用“标记-整理算法”。整理阶段会将存活的对象向一端移动,已防止内存碎片

介绍垃圾收集器?

垃圾收集器是内存回收的具体实现。

Serial GC

最古老的单线程垃圾收集器,必须暂停所有其他的工作线程,会有Stop-The-World问题。 用于Client模式。

ParNew GC

Serial GC的多线程版本,可与CMS配合

CMS(Concurrent Mark Sweep)

并发收集器,减少停顿时间。包括初识标记、并发标记、最终标记、筛选回收。

Parrallel GC

新生代和老年代都是并行进行的,适用吞吐量高的Server模式。

G1 GC(JAVA9默认的垃圾回收器)

兼顾吞吐量和停顿时间的GC。

指令查看

jmap -heap 进程号
进程号可查看Java进程得到
ps -ef|grep java

参考资料

《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》 周志明 著
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html
http://blog.jobbole.com/109170/
https://docs.oracle.com/javase/9/gctuning/toc.htm

猜你喜欢

转载自blog.csdn.net/weixin_42628594/article/details/84979503