代码清单3-5 新生代Minor GC《深入理解Java虚拟机》周志明

使用Client模式虚拟机运行,验证默认的Serial/Serial Old收集器下(ParNew/Serial Old收集器组合的规则也基本一致)的内存分配和回收的策略

大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC

代码清单3-5的testAllocation()方法中,尝试分配3个2MB大小和1个4MB大小的对象,在运行时通过-Xms20M、-Xmx20M、-Xmn10M这3个参数限制了Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下的10MB分配给老年代。-XX:SurvivorRatio=8决定了新生代中Eden区与一个Survivor区的空间比例时8:1,从输出的结果也可以清晰地看到“eden space 8192K、from space 1024K、to space 1024K”的信息,新生代总可用空间9216K(Eden区+1个Survivor区的总容量)。

执行testAllocation()中分配allocation4对象的语句时会发生一次MinorGC,这次GC的结果时新生代6651KB变为148KB,而总内存占用量则几乎没有减少(因为allocation1、allocation2、allocation3三个对象都是存活的,虚拟机几乎没有找到可回收的对象)。这次GC发生的原因是给allocation4分配内存的时候,发现Eden已经被占用了6MB,剩余空间已不足以分配allocation4所需的4MB内存,因此发生Minor GC。GC期间虚拟机又发现已有的3个2MB大小的对象全部无法放入Survivor空间(Survivor空间只有1MB大小),所以只好通过分配担保机制提前转移到老年代去。

这次GC结束后,4MB的allocation4对象顺利分配在Eden中,因此程序执行完的结果是Eden占用4MB(被allocation4占用),Survivor空闲,老年代被占用6MB(被allocation1、allocation2、allocation3占用)。

Java Code : 

package lime.jvm._003._006._001;

/**
 * @Author : Liangmy
 * @Description :
 * @Date : Created in 2020/1/1 下午7:57
 * @Modified By :
 */

/**
 * VM Args : -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:PrintGCDetails -XX:SurvivorRatio=8
 * java -Xmx20M -Xms20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -verbose:gc -Xloggc:./TestAllocation_gc.log lime.jvm._003._006._001.TestAllocation
 * java -Xmx20M -Xms20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -verbose:gc -XX:PretenureSizeThreshold=5242880 lime.jvm._003._006._001.TestAllocation
 */
public class TestAllocation {
    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        testAllocation();
    }

    public static void testAllocation() {
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[2 * _1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        allocation4 = new byte[4 * _1MB]; // 出现一次Minor GC
    }
}

Console :

[GC [DefNew: 6651K->148K(921K), 0.0070106 secs] 6651K->6292K(19456K), 0.0070426 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
 def new generation    total 9216K, used 4326K [0x029d0000, 0x033d0000, 0x033d0000)
  eden space 8291K, 51% used [0x029d0000, 0x02de4828, 0x031d0000)
  from space 1024K, 14% used [0x032d0000, 0x032f5370, 0x033d0000)
  to   space 1024K, 0%  used [0x031d0000, 0x031d0000, 0x032d0000)
 tenured generation total 10240K, used 6144K [0x033d0000, 0x03dd0000, 0x03dd0000)
  the space 10240K, 60% used [0x033d0000, 0x039d0030, 0x039d0200, 0x03dd0000)
 compacting perm gen total 12288K, used 2144K [0x03dd0000, 0x049d0000, 0x07dd0000)
  the space 12288K, 17% used [0x03dd0000, 0x03fe0998, 0x03fe0a00, 0x049d0000) 
No shared spaces configured.

本地测试环境:Mac、JDK8(64bit、Server Mode、Parallel Scavenge/Parallel Old)

Console:

liangmydeMacBook-Pro:_001 liangmy$ java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
liangmydeMacBook-Pro:_001 liangmy$ java -Xmx20M -Xms20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -verbose:gc lime.jvm._003._006._001.TestAllocation
Heap
 PSYoungGen      total 9216K, used 6979K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 8192K, 85% used [0x00000007bf600000,0x00000007bfcd0f38,0x00000007bfe00000)
  from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
  to   space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
 ParOldGen       total 10240K, used 4096K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  object space 10240K, 40% used [0x00000007bec00000,0x00000007bf000010,0x00000007bf600000)
 Metaspace       used 2646K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 286K, capacity 386K, committed 512K, reserved 1048576K

怀疑Parallel Scavenge/Parallel Old 收集器组合的内存分配模式是eden不够的话,没有GC,直接在Old Gen区分配内存空间。或者是4MB算是大对象,直接在Old Gen分配了内存空间。

调整PretenureSizeThreshold(默认值是0,意思是不管多大都是先在eden中分配内存)大小为5MB(-XX:PretenureSizeThreshold=5242880),重新测试。依然没有出现GC。

愁人。。。

注意:PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效,Parallel Scavenge收集器不认识这个参数,Parallel Scavenge收集器一般不需要设置。如果遇到必须使用此参数的场合,可以考虑ParNew加CMS的收集器组合。(3.6.2 大对象直接进入老年代)

使用-XX:+UseSerialGC开关参数指定使用Serial/Serial Old收集器组合测试:

liangmydeMacBook-Pro:_001 liangmy$ java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
liangmydeMacBook-Pro:_001 liangmy$ java -Xmx20M -Xms20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -verbose:gc -XX:+UseSerialGC lime.jvm._003._006._001.TestAllocation
[GC (Allocation Failure) [DefNew: 6815K->278K(9216K), 0.0058263 secs] 6815K->6422K(19456K), 0.0058652 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 def new generation   total 9216K, used 4456K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,  51% used [0x00000007bec00000, 0x00000007bf014930, 0x00000007bf400000)
  from space 1024K,  27% used [0x00000007bf500000, 0x00000007bf5459e0, 0x00000007bf600000)
  to   space 1024K,   0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
 tenured generation   total 10240K, used 6144K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
   the space 10240K,  60% used [0x00000007bf600000, 0x00000007bfc00030, 0x00000007bfc00200, 0x00000007c0000000)
 Metaspace       used 2646K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 286K, capacity 386K, committed 512K, reserved 1048576K

eden space 和 tenured generation的内存空间是一致的,但是def new generation中的from space 中27%的内存占用又是哪个?(书上是14%,这些内存使用到哪里了?)

愁人。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值