-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
发现即使新生代足够分配,大于这个值的大对象也直接在老年代分配。
从而印证了上面文档的说法。
原文链接: https://www.yukx.com/javadev/article/details/2379.html 优科学习网-XX:PretenureSizeThreshold的默认值和作用浅析
-
首先就是创建一个普通的Java工程,起名TrySpring,最终项目如下图:然后在创建两个包分别为service、spring。service用来存放bean、配置类等,spring包用来存放我们手撸的spring注解等在service中创建UserService类,再创建Test类,在Test类中
-
AQS(AbstractQueuedSynchronizer)是一个抽象的队列同步器,通过维护一个共享资源状态(VolatileIntState)和一个先进先出(FIFO)的线程等待队列来实现一个多线程访问共享资源的同步框架。一、AQS原理 AQS为每个共享资源都设置一个共享资源锁
-
word-break:break-all举例一般情况下,元素拥有默认的white-space:normal(自动换行,PS:不换行是white-space:nowrap),当录入的文字超过定义的宽度后会自动换行,但当录入的数据是一堆没有空格的字符或字母或数字(常规数据应该不会有吧,但有些测试人员是会
-
Bigdecimal的初始化这里对比了两种形式,第一种直接value写数字的值,第二种用string来表示 BigDecimal num1 = new BigDecimal(0.005); BigDecimal num2 = new BigDecimal(1000000
-
基本概念定义 双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。双亲委派机制双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载
-
主要看在resouces目录下的路径和mapper接口的路径是否一致。如接口路径:com.yukx.demo.mapper则在resouces目录下的文件路径:com/yukx/demo/mapper, 而不是如图的那个文件