-XX:PretenureSizeThreshold的默认值和作用浅析

简介: -XX:PretenureSizeThreshold的默认值和作用浅析

一、背景

《深入理解Java虚拟机》第93页,3.6.2 大对象直接进入老年代。

讲到大对象主要指字符串和数组,虚拟机提供了一个-XX:PretenureSizeThreshold参数,大于这个值的参数直接在老年代分配。

这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存复制(新生代采用复制算法)。

但是这里没讲清楚默认值是多少,默认会不会“大”对象直接进入老年代。

二、解析

2.1 参考文章
找到了一篇相关问题的文章《Frequently Asked Questions about Garbage Collection in the HotspotTM JavaTM Virtual Machine》

第29条:Do objects ever get allocated directly into the old generation?

In 1.4.1 there two situations where allocation may occur directly into the old generation.

有两种情况,对象会直接分配到老年代。
If an allocation fails in the young generation and the object is a large array that does not contain any references to objects, it can be allocated directly into the old generation. In some select instances, this strategy was intended to avoid a collection of the young generation by allocating from the old generation.

如果在新生代分配失败且对象是一个不含任何对象引用的大数组,可被直接分配到老年代。

通过在老年代的分配避免新生代的一次垃圾回收。

There is a flag (available in 1.4.2 and later) l-XX:PretenureSizeThreshold= that can be set to limit the size of allocations in the young generation. Any allocation larger than this will not be attempted in the young generation and so will be allocated out of the old generation.

XX:PretenureSizeThreshold=<字节大小>可以设分配到新生代对象的大小限制。

任何比这个大的对象都不会尝试在新生代分配,将在老年代分配内存。

The threshold size for 1) is 64k words. The default size for PretenureSizeThreshold is 0 which says that any size can be allocated in the young generation.

PretenureSizeThreshold 默认值是0,意味着任何对象都会现在新生代分配内存。

2.2 实验解析
设置虚拟机参数

-Xms2048m
-Xmx2048m
-Xmn1024m
-XX:+UseConcMarkSweepGC

-XX:SurvivorRatio=8

-Xms表示初始化堆内存

-Xmx 表示最大堆内存

-Xmn表示新生代的内存

-XX:SurvivorRatio=8表示新生代的Eden占8/10,S1和S2各占1/10.

因此Eden的内存大小为:0.8102410241024字节 约为81910241024

上代码

public class Test {

    public static void main(String[] args) throws Exception {

        byte[] array = new byte[700 * 1024 * 1024];//734003216

        for (MemoryPoolMXBean memoryPoolMXBean : ManagementFactory.getMemoryPoolMXBeans()) {

            System.out.println(memoryPoolMXBean.getName() + "  总量:" + memoryPoolMXBean.getUsage().getCommitted() + "   使用的内存:" + memoryPoolMXBean.getUsage().getUsed());
        }

    }
}

可以看到应该被分配到了新生代的Eden区

Code Cache  总量:2555904   使用的内存:1206528
Metaspace  总量:4980736   使用的内存:3426872
Compressed Class Space  总量:524288   使用的内存:371280
Par Eden Space  总量:859045888   使用的内存:785546016
Par Survivor Space  总量:107347968   使用的内存:0
CMS Old Gen  总量:1073741824   使用的内存:0

将数组对象增加到大于Eden区内存大小

byte[] array = new byte[900 1024 1024];
会导致新生代分配失败,直接进入老年代

Code Cache  总量:2555904   使用的内存:1197824
Metaspace  总量:4980736   使用的内存:3426024
Compressed Class Space  总量:524288   使用的内存:371280
Par Eden Space  总量:859045888   使用的内存:34361864
Par Survivor Space  总量:107347968   使用的内存:0
CMS Old Gen  总量:1073741824   使用的内存:943718416

且此时通过jstat -gcutil vmpid命令查看垃圾回收状态,发现并没有YGC.

然后我们将字节数组改回 小于Eden去内存

byte[] array = new byte[700 1024 1024];

并添加启动参数-XX:PretenureSizeThreshold=100000000

Code Cache  总量:2555904   使用的内存:1172160
Metaspace  总量:4980736   使用的内存:3412552
Compressed Class Space  总量:524288   使用的内存:371280
Par Eden Space  总量:859045888   使用的内存:51542800
Par Survivor Space  总量:107347968   使用的内存:0
CMS Old Gen  总量:1073741824   使用的内存:734003216

发现即使新生代足够分配,大于这个值的大对象也直接在老年代分配。

从而印证了上面文档的说法。

三、总结

多查权威参考文档,参考价值更大。

多试验看效果,实践印象才更加深刻。

思路参考自:https://www.jianshu.com/p/f7cde625d849

相关文章
|
1天前
默认值
3.默认值不一样【重点】 局部变量:没有默认值,如果要想使用,必须手动进行赋值 成员变量:如果没有赋值,会有默认值,规则和数组一样 4.内存的位置不一样(了解) 局部变量:位于栈内存 成员变量:位于堆内存 5生命周期不一样(了解)
7 0
|
10天前
默认值不一样
3.默认值不一样【重点】 局部变量:没有默认值,如果要想使用,必须手动进行赋值 成员变量:如果没有赋值,会有默认值,规则和数组一样 4.内存的位置不一样(了解) 局部变量:位于栈内存 成员变量:位于堆内存 5生命周期不一样(了解)
29 8
|
26天前
默认值不一样【重点】
3.默认值不一样【重点】 局部变量:没有默认值,如果要想使用,必须手动进行赋值 成员变量:如果没有赋值,会有默认值,规则和数组一样 4.内存的位置不一样(了解) 局部变量:位于栈内存 成员变量:位于堆内存 5生命周期不一样(了解)
9 0
|
4月前
|
存储 C#
C# 方法详解:定义、调用、参数、默认值、返回值、命名参数、方法重载全解析
方法是一段代码,只有在调用时才会运行。 您可以将数据(称为参数)传递给方法。 方法用于执行某些操作,也被称为函数。 为什么使用方法?为了重用代码:定义一次代码,然后多次使用。
44 0
|
9月前
默认移动构造、默认移动赋值自动生成的条件
默认移动构造、默认移动赋值自动生成的条件
103 0
|
6月前
|
Linux Shell C语言
SO_RCVBUF和SO_SNDBUF默认值
SO_RCVBUF和SO_SNDBUF默认值
81 0
|
PHP 开发者
参数默认值|学习笔记
快速学习参数默认值
73 0
参数默认值|学习笔记
C++中转换构造函数与默认函数的优先级
C++中转换构造函数与默认函数的优先级
|
小程序
小程序怎么设置默认值为0,使用if即可
小程序怎么设置默认值为0,使用if即可
125 0
|
编译器 C#
为字段设置初始值
为字段设置初始值
110 0