GC 回收参数问题

2016-10-21 12:39:50 +08:00
 thinkmore

我在我的 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 虚拟机规范没有发现哪里有对这种情况的说明,是我做的方法不对,理解不对还是怎样的,求大家帮忙解答下。

2288 次点击
所在节点    问与答
10 条回复
thinkmore
2016-10-21 14:09:41 +08:00
使用的系统是 win64 位企业版、 jdk1.7.0_55 、 Luna Service Release 2 (4.4.2)。
thinkmore
2016-10-21 23:28:48 +08:00
@SoloCompany 给看下,我的哥
SoloCompany
2016-10-21 23:53:09 +08:00
擦,为啥我会被艾特到的
第一反应,你为啥不查一下是不是 jvm 实现限制了 heap 的下限呢
第二,如果文档没说到,那就只能找源码区确认了, jvm 7 的实现应该是和 openjdk 的实现基本上一致吧
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
2016-10-22 15:18:13 +08:00
@SoloCompany 谢谢。
关于你说的两个方法
1. 我没有找到任何资料关于这个下限的设置
2. 源码确认你说的是 C++实现的代码吗?如果是这个,个人能力有限,看不太懂 c++代码。

还有 @你,是因为我觉得你牛。
再次感谢
thinkmore
2016-10-22 17:27:49 +08:00
@SoloCompany jdk8 中应该有很多变化,方法区都变化了。
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
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
SoloCompany
2016-10-23 01:00:04 +08:00
thinkmore
2016-10-23 17:01:24 +08:00
@SoloCompany 谢谢,找到原因了!

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/314383

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX