为了能更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。
执行代码清代3-8中的testTenuringThreshold2()方法,并设置-XX:MaxTenuringThreshold=15,会发现运行结果中Survivor的空间占用仍然为0%,而老年代比预期增加6%,也就是说,allocation1、allocation2对象直接进入了老年代,而没有等到15岁的临界年龄。因为这两个对象加起来已经达到了512KB,并且它们是同年的,满足同年对象达到Survivor空间的一半规则。我们只要注释掉其中一个对象new操作,就会发现另外一个不会晋升到老年代中去了。
代码清单3-8 动态对象年龄判定:
package lime.jvm._003._006._004;
/**
* @Author : Liangmy
* @Description :
* @Date : Created in 2020/1/5 下午9:50
* @Modified By :
* VM Args : -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+UseSerialGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintTenuringDistribution
* java -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+UseSerialGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintTenuringDistribution lime.jvm._003._006._004.TestTenuringThreshold2
*/
public class TestTenuringThreshold2 {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
testTenuringThreshold2();
}
private static void testTenuringThreshold2() {
byte[] allocation1, allocation2, allocation3, allocation4;
// eden(8MB) 0MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB)
allocation1 = new byte[_1MB / 4]; // eden(8MB) 0.25MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB)
// allocation1 + allocation2 大于 survivor 空间的一半
allocation2 = new byte[_1MB / 4]; // eden(8MB) 0.25MB(0) 0.25MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 0MB
allocation3 = new byte[_1MB * 4]; // eden(8MB) 0.25MB(0) 0.25MB(0) 4MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 0MB
// allocation1 + allocation2 + allocation3 + allocation4 大于 eden
// 触发GC
// allocation1、allocation2 进入survivor,但是allocation1 + allocation2 大于 survivor 空间的一半,allocation1、allocation2对象都直接进入了老年代
// allocation3 大于survivor,直接进入老年代
// eden(8MB) 0MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB
// 手动调用GC测试 System.gc();
allocation4 = new byte[_1MB * 4]; // eden(8MB) 4MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB(和预想中的不一样)
allocation4 = null;
// 4MB(不可达) + 4MB 大于 eden
// 触发GC,eden(8MB) 0MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB
allocation4 = new byte[_1MB * 4]; // eden(8MB) 4MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB
}
}
运行结果:
本地测试结果:
localhost:_004 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)
localhost:_004 liangmy$ java -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+UseSerialGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintTenuringDistribution lime.jvm._003._006._004.TestTenuringThreshold2
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 15)
- age 1: 809360 bytes, 809360 total
: 5279K->790K(9216K), 0.0050284 secs] 5279K->4886K(19456K), 0.0050733 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 15 (max 15)
: 4886K->0K(9216K), 0.0014409 secs] 8982K->4884K(19456K), 0.0014642 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4178K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
eden space 8192K, 51% used [0x00000007bec00000, 0x00000007bf014930, 0x00000007bf400000)
from space 1024K, 0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
to space 1024K, 0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
tenured generation total 10240K, used 4884K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
the space 10240K, 47% used [0x00000007bf600000, 0x00000007bfac5290, 0x00000007bfac5400, 0x00000007c0000000)
Metaspace used 2646K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 286K, capacity 386K, committed 512K, reserved 1048576K
思考:
allocation4 = new byte[_1MB * 4]; // eden(8MB) 4MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB(和预想中的不一样)
???愁人。。。
code :
package lime.jvm._003._006._004;
/**
* @Author : Liangmy
* @Description :
* @Date : Created in 2020/1/5 下午9:50
* @Modified By :
* VM Args : -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+UseSerialGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintTenuringDistribution
* java -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+UseSerialGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintTenuringDistribution lime.jvm._003._006._004.TestTenuringThreshold2
*/
public class TestTenuringThreshold2 {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
testTenuringThreshold2();
}
private static void testTenuringThreshold2() {
byte[] allocation1, allocation2, allocation3, allocation4;
// eden(8MB) 0MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB)
allocation1 = new byte[_1MB / 4]; // eden(8MB) 0.25MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB)
// allocation1 + allocation2 大于 survivor 空间的一半
allocation2 = new byte[_1MB / 4]; // eden(8MB) 0.25MB(0) 0.25MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 0MB
allocation3 = new byte[_1MB * 4]; // eden(8MB) 0.25MB(0) 0.25MB(0) 4MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 0MB
// allocation1 + allocation2 + allocation3 + allocation4 大于 eden
// 触发GC
// allocation1、allocation2 进入survivor,但是allocation1 + allocation2 大于 survivor 空间的一半,allocation1、allocation2对象都直接进入了老年代
// allocation3 大于survivor,直接进入老年代
// eden(8MB) 0MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB
// 手动调用GC测试 System.gc();
allocation4 = new byte[_1MB * 4]; // eden(8MB) 4MB(0) from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB(和预想中的不一样)
// allocation4 = null;
// 4MB(不可达) + 4MB 大于 eden
// 触发GC,eden(8MB) 0MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB
// allocation4 = new byte[_1MB * 4]; // eden(8MB) 4MB from survivor(1MB) 0MB to survivor(1MB) 0MB tenure gen(10MB) 4.5MB
}
}
GC log :
??? 愁人。。。
在为allocation4分配空间之前先手动调用GC的话,符合猜想。。。so.why?