06 “eden没有发生minor gc, 对象直接分配在了old gen“ 的调试

2024-05-28 15:32

本文主要是介绍06 “eden没有发生minor gc, 对象直接分配在了old gen“ 的调试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

呵呵 最近在看这样一篇文章的时候, eden区没有发生minor gc,对象直接分配在了old gen 

看到了 R大 的叱咤风云, 讲解的非常细致, 十分令人佩服, 然后 若是想有所收获, 还得 构造一下这个情况, 复现一下, 然后 调试着走一次, 才能 有所收获, 嘿嘿 

当然 由于 vm 版本不一样, 因此 下面的测试用例的相关 选项 我这里做了一些 调整 

 

一下代码, 截图 基于 jdk9 

 

 

测试用例如下 

package com.hx.test04;/*** AllocationTest** @author Jerry.X.He <970655147@qq.com>* @version 1.0* @date 2020-03-06 15:24*/
public class Test03AllocationTest {/*** constants*/private static final int _1KB = 1024;private static final int _1MB = _1KB * 1024;// Test03AllocationTest// refer : https://hllvm-group.iteye.com/group/topic/38293/*** -Xint -Xmx100M -XX:+UseParallelGC -XX:-UseTLAB -XX:+PrintGCDetails -XX:MaxNewSize=40M -XX:NewSize=28M*/public static void main(String[] args) {testAllocation();}// testAllocationpublic static void testAllocation() {byte[] byte1 = new byte[_1MB*5];byte[] byte2 = new byte[_1MB*10];byte1 = null;byte2 = null;byte[] byte3 = new byte[_1MB*5];byte[] byte4 = new byte[_1MB*10];byte3 = null;byte4 = null;byte[] byte5 = new byte[_1MB*15];}}

跑的时候 需要加上 如上的相关 vm 参数, 但是 普通的 跑这个 测试用例 看不到太多的东西, 需要结合 具体的调试, 才能 了解到 R大 所说的一系列描述的意思  

 

 

第一个字节数组的数据分配 

可以看到, 这里是 第一个 "new byte[_1MB*5]", length 为 5M, size 怎么看起来和 length 没什么关系啊 ? 
呵呵 我最开始看到这里也奇怪, 直到看了一下 "size_t size = typeArrayOopDesc::object_size(layout_helper(), length);" 的代码 

原来这里的 size = (length + header_size) / WordPerBytes 计算出来的, BytesPerWord 是指一个字对应多少个字节, 64位操作系统中其值为 8 

呵呵 我最开始看觉得有些奇怪是因为 我发现这个 size 怎么比 length 大这么多??, 不就装字节数据 + mark + klass + length 么, 咋个会多出这么多, 后来仔细一看 原来 size 是比 length 少了一位 

 

 

第一次字节数组的分配细节 

分配之前 young_gen 的 used 为 4.18M, capacity 为 24.50M(eden:21M, from:3.5M)

eden 的 used 为 4.18M, capacity 为 21M 

我们这里分配的是 5M, 可以分配, 就直接从 young_gen 里面分配了 

 

创建第一个字节数组之后 young_gen used 为 9.18M 

 

 

第二次数组分配的细节 

分配之前 young_gen 的 used 为 9.18M, capacity 为 24.50M(eden:21M, from:3.5M)

eden 的 used 为 9.18M, capacity 为 21M 

堆的相关数据 和 第一次数组分配之后的结果一样, 只是这里需要分配的字节数组 变成了 10M 

这里 young_gen 依然能够分配第二个数组 

 

分配之后 young_gen used 为 19.18M 

 

 

第三次数组分配的细节  

分配之前 young_gen 的 used 为 19.18M, capacity 为 24.50M(eden:21M, from:3.5M)

eden 的 used 为 19.18M, capacity 为 21M 

到这里 young_gen 分配不了 这个 5M 的字节数组了 

 

后面尝试 在 young_gen 再重新分配, 失败 

尝试在 old_gen 分配空间, 不满足条件 

gc_locker_stalled_count, GCLocker::is_active_and_needs_gc 也不满足条件 

 

尝试在 old_gen 分配空间的条件如下 

这里的 GCLocker::is_active_and_needs_gc 和 _death_march_count 在这里不满足条件 

 

R大 评论中也是这个判断, 只是由于 版本不一样, 细节上存在一些 差异 

 

然后触发了一次 minor gc 

 

VM_ParallelGCFailedAllocation 处理了之后 为第三个字节数组 分配了空间 

分配之后 eden 的 used 为 5.00M 

 

 

第四次数组分配细节如下 

分配之前 young_gen 的 used 为 5.00M, capacity 为 24.50M(eden:21M, from:3.5M)

eden 的 used 为 5.00M, capacity 为 21M 

可以明显看到 eden 是足以分配 这个 10M 的字节数组的, 因此这里 就在 young_gen 分配 

 

分配之后 eden 的 used 为 15.00M 

 

 

第五次数组分配的细节

分配之前 young_gen 的 used 为 15.00M, capacity 为 24.50M(eden:21M, from:3.5M)

eden 的 used 为 15.00M, capacity 为 21M 

在 young_gen 已经分配不下 这里的 15M 的数组 

 

根据上面的 是否需要在 old_gen 分配的条件之一, "size > eden_space.capacity_in_words/2", 来比较的话 

我们这里 size 是 1966082, eden_space.capacity_in_words/2 为 1376256, 是符合 在 old_gen 分配的条件的, 因此 这里第五个 字节数组 就在 old_gen 分配了 

这上面的 比较还可以换一个方式, 上面的比较的单位是 字, 我们换成字节的话 会更清晰一些, eden 的空间是 21 M, 一半为 10.5M, 然后 这里申请的空间为 15M, 15M > 10.5M, 因此 可以在 old_gen 里面分配 

 

 

完 

 

 

引用

eden区没有发生minor gc,对象直接分配在了old gen

这篇关于06 “eden没有发生minor gc, 对象直接分配在了old gen“ 的调试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1010965

相关文章

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

使用Python自建轻量级的HTTP调试工具

《使用Python自建轻量级的HTTP调试工具》这篇文章主要为大家详细介绍了如何使用Python自建一个轻量级的HTTP调试工具,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录一、为什么需要自建工具二、核心功能设计三、技术选型四、分步实现五、进阶优化技巧六、使用示例七、性能对比八、扩展方向建

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

Java实现将byte[]转换为File对象

《Java实现将byte[]转换为File对象》这篇文章将通过一个简单的例子为大家演示Java如何实现byte[]转换为File对象,并将其上传到外部服务器,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言1. 问题背景2. 环境准备3. 实现步骤3.1 从 URL 获取图片字节数据3.2 将字节数组

Javascript访问Promise对象返回值的操作方法

《Javascript访问Promise对象返回值的操作方法》这篇文章介绍了如何在JavaScript中使用Promise对象来处理异步操作,通过使用fetch()方法和Promise对象,我们可以从... 目录在Javascript中,什么是Promise1- then() 链式操作2- 在之后的代码中使

MyBatis的配置对象Configuration作用及说明

《MyBatis的配置对象Configuration作用及说明》MyBatis的Configuration对象是MyBatis的核心配置对象,它包含了MyBatis运行时所需的几乎所有配置信息,这个对... 目录MyBATis配置对象Configuration作用Configuration 对象的主要作用C

SpringBoot实现导出复杂对象到Excel文件

《SpringBoot实现导出复杂对象到Excel文件》这篇文章主要为大家详细介绍了如何使用Hutool和EasyExcel两种方式来实现在SpringBoot项目中导出复杂对象到Excel文件,需要... 在Spring Boot项目中导出复杂对象到Excel文件,可以利用Hutool或EasyExcel