jvm垃圾回收-标记复制

一.目的
与标记清除相比,不会产生内存碎片。

二.适用场景
对象生命周期短,适合新生代。

三.基本流程
整个jvm堆分为年轻代,老年代,永久代。

其中年轻代被分成:eden,s0,s1
默认大小比例是:8:1:1。
即能够保证在分配新对象时,新生代大小80%可用于分配。

新生代与老年代比例是:25%新生代及75%老年代。
当eden满了的时候就触发年轻代的垃圾回收。

垃圾回收流程如下:
1.使用根搜索算法,从线程栈,方法区中静态变量引用,等去搜索当前有效的gc root引用。(stop the world)
2.对得到的gc root,分别遍历出所有能够到达的对象集合。这些对象集合不会被垃圾回收。这些对象集合记入到一个内存集合中。
3.扫描eden和其中的一个s0或s1,然后看对应对象在集合中是否存在,存在则将其拷贝到另一块survior区。
4.所有存活对象都到另一块survior区后(这里假设是s0),可以清除之前的survior区(s1)及eden区。
这步可能发生,survior区不够放,则会将这部分存活对象提前迁移到老年代。


四.垃圾回收实例
假设当前堆大小为:20M,年轻代:10M,eden为:8M,s0,s1各为1M。

设置参数为:
-server -Xms20M -Xmx20M -Xmn10M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-XX:+PrintGCDetails -Xloggc:/Users/zhao/Documents/temp/jvm/gc.log

测试代码:
public class PutInEden {

@SuppressWarnings("unused")
public static void main(String[] args) {
byte[] b1, b2, b3, b4, b5, b6;// 定义变量
b1 = new byte[1024 * 1024];
b2 = new byte[1024 * 1024];
b3 = new byte[1024 * 1024];
b4 = new byte[1024 * 1024];
b5 = new byte[1024 * 1024];
b6 = new byte[1024 * 1024 * 2];
byte[] b7 = new byte[1024 * 1024]; //加上这行代码,共分配8M+24字节

}
}

需要注意的是:new byte[1024 * 1024];,占用的内存是1024*1024+24字节=1048600。
即24字节,用于存储数组长度。

以上代码会发生young gc,gc日志如下:
CommandLine flags: -XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=6 -XX:NewSize=10485760 -XX:OldPLABSize=16 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
0.086: [GC (Allocation Failure) 0.086: [ParNew: 7676K->314K(9216K), 0.0049103 secs] 7676K->7484K(19456K), 0.0049906 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
Heap
par new generation total 9216K, used 1664K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
eden space 8192K, 16% used [0x00000007bec00000, 0x00000007bed51948, 0x00000007bf400000)
from space 1024K, 30% used [0x00000007bf500000, 0x00000007bf54ea18, 0x00000007bf600000)
to space 1024K, 0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
concurrent mark-sweep generation total 10240K, used 7170K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
Metaspace used 2642K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 286K, capacity 386K, committed 512K, reserved 1048576K

由日志看到,
0.086: [GC (Allocation Failure) 0.086: [ParNew: 7676K->314K(9216K), 0.0049103 secs] 7676K->7484K(19456K), 0.0049906 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
这里发生了eden区分配内存失败的情况。由于s0及s1不足以存放存活对象,相关的对象被移入到old区。

五.存在的坑
应用中,如果发现频繁的年轻代gc,而每次gc后,年轻代基本没变化,那么有可能出现了内存泄露。
这时,可以将其中一台服务器不对外,然后dump出内存映像进行分析。
常见的内存泄露是某个集合,引用了很多已经不在用的对象。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值