JVM垃圾收器
JVM垃圾收集器收集器采用分代收集算法,堆被划分为新生代和老年代。新生代主要存储新创建的对象和尚未进入老年代的对象。老年代存储经过多次新生代GC(Minor GC)任然存活的对象。
新生代
程序新创建的对象都是从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(通常又称S0和S1或From和To)构成,可通过-Xmn参数来指定新生代的大小,也可以通过-XX:SurvivorRation来调整Eden Space及Survivor Space的大小。
老年代
用于存放经过多次新生代GC任然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代,主要有两种情况:①.大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。②.大的数组对象,切数组中无引用外部对象。 老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。
Young Generation Eden + From Space + To Space
Eden 存放新生的对象
Survivor Space (from to ) 有两个,存放每次垃圾回收后存活的对象
Old Generation Old Space 生命周期长的存活对象
垃圾收集执行规则
对象内存一般在Eden区中分配,大对象(数组,长字符串)在老年代分配内存,当Eden内存不足时会发起MinorGC,发起前会检查老年代最大连续空间是否足够新生代对象空间(这也称为空间分配担保),因为是采用复制算法将不回收的对象复制到Survivor区,Survivor区如果无法容纳就会复制到老年代;如果Survivor区对象通过一次MinorGc,年龄计数器+1,年龄超过设置的阈值(-XX:MaxTenuringThreshold=15)后就会进入老年代。
垃圾收集器回收对象
通俗讲,就是不可能再被任何途径使用的对象就会被垃圾收集器回收,现在常见的垃圾收集器采用的收集算法有:
引用计数算法: 对象中添加引用计数器,有引用+1,引用失效-1,计数器为0表示未被引用可以回收
可达性分析算法:通过成为GC Root对象作为起点,从根节点搜索到达子节点的路径称为引用链,若Gc Root 到对象不可达,则判 定对象为可回收。
Java垃圾收集器采用可达性分析算法,标记为可回收对象至少经历两次标记过程:
a. 判断Gc Root引用链是否可达,不可达情况下判断是否有必要对象的finalize(),若有,则将这个对象放置F-Queue队列,稍后由虚拟机自动建立的低优先级的Finalizer线程去触发finalize();
b. GC会对F-Queue中对象进行第二次小规模标记,对象可以通过finalize()拯救自己,否则就会被回收。
垃圾收集算法细节
标记清除算法:Mark-Sweep 标记出所有的需要回收的对象,统计回收所有回收的对象;缺点是效率不高,会产生大量的不连续内存碎片,导致分配大对象内存时无法获取连续的内存空间
复制算法:使用指针实现内存空间的复制清理,HotSpot使用此种算法,Java堆内存分为新生代和老年代, 新生代默认划分Eden&Survivor(8:1),GC触发时,会将活动对象复制到Survivor区,当Survivor空间不够时会进入老年代空间,比如长期存活对象(Survivor区对象通过一次MinorGc,年龄计数器+1,年龄超过进入老年代),大对象(长字符串、数组); 缺点:对象存活率较高时就会进行频繁的复制,效率会变低
标记整理算法:在标记清除算法基础上,将存活的对象移向一端,然后直接清理端边界以外的内存
分代收集算法:就是将以上几种算法择优分区使用,新生代(Minor GC)中使用复制算法,老年代(Major GC)使用标记 整理算法进行回收