对象已经死了吗
- 在Heap中存放着Java世界中几乎所有的对象的实例,垃圾回收器在堆进行回收之前第一件事就是要确定这些对象之中哪些还“存活着”,哪些已经“死去”(即不可能再被任何途径使用的对象)。然后回收无用对象所占的内存。
发现无用的对象:
- 引用计数算法(Referrence Counting): 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用值失效时就减1;任何时刻计数器为0的对象都是不可能再被使用的。这种方法实现简单,判定效率也高。但是,至少主流的Java虚拟机不使用它来管理内存,其主要原因是他很难解决对象之间相互循环引用的问题。
- 可达性分析算法(Reachability Analysis): 通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(即从GC Roots到这个对象不可达)时,则证明此对象是不可用的。
在Java中,可作为GC Roots的对象包括下面几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象。
通过分代垃圾回收机制:
根据对象存活周期的不同将内存划分为年轻代(Young Generation),年老代(Tenured/Old Generation),持久代(Permanent Generation)。年轻区分为Eden(伊甸园)区, Survivor区。年老代放存活周期长的对象。持久代属于方法区。
垃圾回收三种:
Minor GC:
新生代GC,用于清理年轻代区域。Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到“Survicor1”,“Survivor2”区中(这两个区域,大小空间相同,同一时刻Survivor1和Survivor2只有一个在用,一个为空)
Major GC:
用于清理老年代区域。
Full GC:
用于全面清理年轻代,老年代区域。成本较高,会对系统性能产生极大的影响。平时的性能优化,垃圾回收优化指的就是对Full GC优化。
过程:
1.新建一个对象会放在Eden中。
2.Eden满了后,就会触发垃圾回收Minor GC通过引用可达先算一遍清理无用对象,同时将存活下来的对象放在Survivor区,如Survivor1。
3.随着程序运行继续添加对象,Eden再次满了后,将S1中存活下来的对象存在另一个Survivor中如Survivor2。同时将Eden中存活下来的对象复制到S1中,保证Eden和S1均被清空。
4.重复多次后(默认15个周期),Survivor中没有被清理的对象,这时对象就老了,被复制到老年代区。
5.当Old区在一定比例会启动Major GC。
当Old区满了后会触发Full GC。
JVM调优指的就是Full GC:
在对JVM调优的过程中,很大一部分工作就是对于Full GC的调节。
导致Full GC的原因:
1.老年代(Tenured)被写满。
2.持久代(Perm)被写满。
3.System.gc()被显示调用(程序建议GC启动,不是调用GC)
4.上一次GC之后Heap的各域分配策略动态变化。