登录 |  注册
首页 >  编程语言 >  Spring开发实战学习笔记 >  -XX:PretenureSizeThreshold的默认值和作用浅析

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

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

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

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

一、解析

1.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 wher 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=<byte size> 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,意味着任何对象都会现在新生代分配内存。

1.2 实验解析

设置虚拟机参数

-Xms2048m
-Xmx2048m
-Xmn1024m
-XX:+UseConcMarkSweepGC
-XX:SurvivorRatio=8
  • -Xms表示初始化堆内存

  • -Xmx 表示最大堆内存

  • -Xmn表示新生代的内存

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

因此Eden的内存大小为:0.8*1024*1024*1024字节 约为819**1024*1024

上代码

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

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

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

上一篇: Mybatis无法找到xml文件,Invalid bound statement (not found)
下一篇: 从零开始-手写模拟Spring框架 (附教程源码)
推荐文章
  • 项目中,有些函数需要处理某个服务的返回结果,而在对函数单元测试的时候,又不能启动那些服务,这里就可以利用Mockito工具,其中有如下三种注解:@InjectMocks:创建一个实例,简单的说是这个Mock可以调用真实代码的方法,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。
  • 雪花算法(Snowflake)是由Twitter开发的一种分布式ID生成算法,旨在为分布式系统提供一种简单而有效的方式,以生成全局唯一、有序且可排序的64位整数ID。这种ID通常用作数据库记录的主键或其他需要唯一标识符的场景。雪花算法生成的64位ID结构如下:最高位(第64位):固定为0,因为64位
  • 在HTML中,如果你想让一个输入框(input元素)不可编辑,你可以通过设置其readonly属性来实现。示例如下:input type="text" value="此处内容不可编辑" readonly在上述代码中,readonly属性使得用户无法修改输入框中的内容。另外,如果你希望输入框完全不可交
  • ASP.NET教程ASP.NET又称为ASP+,基于.NETFramework的Web开发平台,是微软公司推出的新一代脚本语言。ASP.NET是一个使用HTML、CSS、JavaScript和服务器脚本创建网页和网站的开发框架。ASP.NET支持三种不一样的开发模式:WebPages(Web页面)、
  • C# 判断判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。下面是大多数编程语言中典型的判断结构的通常形式:判断语句C#提供了以下类型的判断语句。点击链接查看每个语句的细节。语句描述if语句一个 if语句 由一个布尔表达式后跟
  • C#循环有的时候,可能需要多次执行同一块代码。通常情况下,语句是顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推。编程语言提供了允许更为复杂的执行路径的多种控制结构。循环语句允许我们多次执行一个语句或语句组,下面是大多数编程语言中循环语句的通常形式:循环类型C#提供了以下几种循环类型
学习大纲