V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
thinkmore
V2EX  ›  问与答

GC 回收参数问题

  •  
  •   thinkmore · 2016-10-21 12:39:50 +08:00 · 2288 次点击
    这是一个创建于 2959 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我在我的 eclipse 中进行开发进行 JVM 参数测试,但是打印出来的 gc 信息和我预想(从书上看)的不一样,找了很多答案也不知道为什么,求大神指点呀!

    public class OutOfMemoryTest {
    	@Test
    	public void heapOutOfMemory() throws InterruptedException {
    		//-Xmx4M -Xms4M -Xmn2M -XX:+PrintGCDetails
    		//Thread.sleep(40000);
    		byte[] b = new byte[2*1024*1024];
    	}
    }
    

    按照道理来说我设置堆得大小为 4M ,且不可扩展, young 区的大小为 2M ,那么 old 区的大小也应该为 2M,但是为什么 eclipse 中打印出来的 gc 信息是这样的?

    Heap
     PSYoungGen      total 1536K, used 745K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
      eden space 1024K, 25% used [0x00000000ffe00000,0x00000000ffe40628,0x00000000fff00000)
      from space 512K, 95% used [0x00000000fff80000,0x00000000ffffa020,0x0000000100000000)
      to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
     ParOldGen       total 4608K, used 2993K [0x00000000ff800000, 0x00000000ffc80000, 0x00000000ffe00000)
      object space 4608K, 64% used [0x00000000ff800000,0x00000000ffaec558,0x00000000ffc80000)
     PSPermGen       total 262144K, used 5380K [0x00000000ef800000, 0x00000000ff800000, 0x00000000ff800000)
      object space 262144K, 2% used [0x00000000ef800000,0x00000000efd41350,0x00000000ff800000)
    

    我用 jmap 打印出来的结果也是这样, old 区的大小已经大于我整个堆得大小了? 然后我将代码修改成了这样

    @Test
    	public void heapOutOfMemory() throws InterruptedException {
    		//-Xmx64M -Xms64M -Xmn32M -XX:+PrintGCDetails
    		byte[] b = new byte[32*1024*1024];
    	}
    
    

    打印出来的信息就正确了, old 区的大小就是 32M 了。打印结果如下:

    Heap
     PSYoungGen      total 28672K, used 1966K [0x00000000fe000000, 0x0000000100000000, 0x0000000100000000)
      eden space 24576K, 8% used [0x00000000fe000000,0x00000000fe1eb9c0,0x00000000ff800000)
      from space 4096K, 0% used [0x00000000ff800000,0x00000000ff800000,0x00000000ffc00000)
      to   space 4096K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x0000000100000000)
     ParOldGen       total 32768K, used 1292K [0x00000000fc000000, 0x00000000fe000000, 0x00000000fe000000)
      object space 32768K, 3% used [0x00000000fc000000,0x00000000fc1432e8,0x00000000fe000000)
     PSPermGen       total 262144K, used 5421K [0x00000000ec000000, 0x00000000fc000000, 0x00000000fc000000)
      object space 262144K, 2% used [0x00000000ec000000,0x00000000ec54b678,0x00000000fc000000)
    

    但是我还是有一个疑问:为什么 eden:from 的比例不是 8 : 1. 我看了 jvm 虚拟机规范没有发现哪里有对这种情况的说明,是我做的方法不对,理解不对还是怎样的,求大家帮忙解答下。

    10 条回复    2016-10-23 17:01:24 +08:00
    thinkmore
        1
    thinkmore  
    OP
       2016-10-21 14:09:41 +08:00
    使用的系统是 win64 位企业版、 jdk1.7.0_55 、 Luna Service Release 2 (4.4.2)。
    thinkmore
        2
    thinkmore  
    OP
       2016-10-21 23:28:48 +08:00
    @SoloCompany 给看下,我的哥
    SoloCompany
        3
    SoloCompany  
       2016-10-21 23:53:09 +08:00   ❤️ 1
    擦,为啥我会被艾特到的
    第一反应,你为啥不查一下是不是 jvm 实现限制了 heap 的下限呢
    第二,如果文档没说到,那就只能找源码区确认了, jvm 7 的实现应该是和 openjdk 的实现基本上一致吧
    SoloCompany
        4
    SoloCompany  
       2016-10-22 00:05:48 +08:00
    其实也不用去确认,你没有看到 OutOfMemoryError 就足够说明问题了,配置根本就被忽略了
    我在 java8 下执行的结果并不存在你说的现象

    java -Xmx4M -Xms4M -Xmn2M -XX:+PrintGCDetails -cp /private/var/folders/vv/ff28c0z560n407mjb5_x4c9h0000gn/T/CodeRunner Untitled
    [GC (Allocation Failure) [PSYoungGen: 672K->496K(1536K)] 672K->512K(3584K), 0.0022537 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
    [GC (Allocation Failure) [PSYoungGen: 496K->480K(1536K)] 512K->496K(3584K), 0.0007598 secs] [Times: user=0.01 sys=0.01, real=0.00 secs]
    [Full GC (Allocation Failure) [PSYoungGen: 480K->0K(1536K)] [ParOldGen: 16K->428K(2048K)] 496K->428K(3584K), [Metaspace: 2727K->2727K(1056768K)], 0.0062196 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
    [GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 428K->428K(3584K), 0.0005307 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 428K->417K(2048K)] 428K->417K(3584K), [Metaspace: 2727K->2727K(1056768K)], 0.0042598 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at Untitled.main(Untitled 3.java:3)
    Heap
    PSYoungGen total 1536K, used 30K [0x00000007bfe00000, 0x00000007c0000000, 0x00000007c0000000)
    eden space 1024K, 2% used [0x00000007bfe00000,0x00000007bfe07890,0x00000007bff00000)
    from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
    to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
    ParOldGen total 2048K, used 417K [0x00000007bfc00000, 0x00000007bfe00000, 0x00000007bfe00000)
    object space 2048K, 20% used [0x00000007bfc00000,0x00000007bfc685d0,0x00000007bfe00000)
    Metaspace used 2759K, capacity 4486K, committed 4864K, reserved 1056768K
    class space used 300K, capacity 386K, committed 512K, reserved 1048576K
    thinkmore
        5
    thinkmore  
    OP
       2016-10-22 15:18:13 +08:00
    @SoloCompany 谢谢。
    关于你说的两个方法
    1. 我没有找到任何资料关于这个下限的设置
    2. 源码确认你说的是 C++实现的代码吗?如果是这个,个人能力有限,看不太懂 c++代码。

    还有 @你,是因为我觉得你牛。
    再次感谢
    thinkmore
        6
    thinkmore  
    OP
       2016-10-22 17:27:49 +08:00
    @SoloCompany jdk8 中应该有很多变化,方法区都变化了。
    SoloCompany
        7
    SoloCompany  
       2016-10-22 20:03:48 +08:00
    @thinkmore java7 运行的结果, map 显示的很清楚啊,显然你配置成 4MB 的 heap 是无效的,被自动调整为 8MB

    $JAVA7_HOME/bin/jmap -heap 95786
    Attaching to process ID 95786, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 24.79-b02

    using thread-local object allocation.
    Parallel GC with 4 thread(s)

    Heap Configuration:
    MinHeapFreeRatio = 0
    MaxHeapFreeRatio = 100
    MaxHeapSize = 8388608 (8.0MB)
    NewSize = 2097152 (2.0MB)
    MaxNewSize = 2097152 (2.0MB)
    OldSize = 5439488 (5.1875MB)
    NewRatio = 2
    SurvivorRatio = 8
    PermSize = 21757952 (20.75MB)
    MaxPermSize = 85983232 (82.0MB)
    G1HeapRegionSize = 0 (0.0MB)

    … ...
    thinkmore
        8
    thinkmore  
    OP
       2016-10-22 22:12:47 +08:00
    @SoloCompany 我用 jmap 打印出来确实是调整了,但是为什么会被动态调整呢?

    今天我查阅了 oracle 的官方资料,上面只说了 Parallel Scavenge(64 位系统 server 模式下的默认收集器)因为默认开启了 UseAdaptiveSizePolicy 参数,所以才会对新生代的大小进行动态调整,但是为啥我使用其他收集器测试正如 jmap 中打印出来的参数那样 maxHeapSize 被修改成了 8M,我设置的 4M 没起作用。我使用这样的参数进行模拟:
    ```
    //-Xmx6M -Xms6M -XX:+PrintGCDetails -XX:-UseAdaptiveSizePolicy -XX:+UseParNewGC
    Heap Configuration:
    MinHeapFreeRatio = 40
    MaxHeapFreeRatio = 70
    MaxHeapSize = 8388608 (8.0MB)
    NewSize = 1310720 (1.25MB)
    MaxNewSize = 17592186044415 MB
    OldSize = 5439488 (5.1875MB)
    NewRatio = 2
    SurvivorRatio = 8
    PermSize = 21757952 (20.75MB)
    MaxPermSize = 85983232 (82.0MB)
    G1HeapRegionSize = 0 (0.0MB)

    Heap Usage:
    New Generation (Eden + 1 Survivor Space):
    capacity = 1900544 (1.8125MB)
    used = 693800 (0.6616592407226562MB)
    free = 1206744 (1.1508407592773438MB)
    36.50533741918103% used
    Eden Space:
    capacity = 1703936 (1.625MB)
    used = 497192 (0.47415924072265625MB)
    free = 1206744 (1.1508407592773438MB)
    29.179030198317307% used
    From Space:
    capacity = 196608 (0.1875MB)
    used = 196608 (0.1875MB)
    free = 0 (0.0MB)
    100.0% used
    To Space:
    capacity = 196608 (0.1875MB)
    used = 0 (0.0MB)
    free = 196608 (0.1875MB)
    0.0% used
    tenured generation:
    capacity = 4194304 (4.0MB)
    used = 1415024 (1.3494720458984375MB)
    free = 2779280 (2.6505279541015625MB)
    33.73680114746094% used
    Perm Generation:
    capacity = 21757952 (20.75MB)
    used = 5838448 (5.5679779052734375MB)
    free = 15919504 (15.182022094726562MB)
    26.833628459149097% used

    ```

    而且 eden:from 的比例也不是 8:1 呀!

    参考文档:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

    哥,如果可以的话,加个 q 吧。 353003874
    thinkmore
        10
    thinkmore  
    OP
       2016-10-23 17:01:24 +08:00
    @SoloCompany 谢谢,找到原因了!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5598 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 06:44 · PVG 14:44 · LAX 22:44 · JFK 01:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.