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

相关文章

JavaScript对象转数组的三种方法实现

《JavaScript对象转数组的三种方法实现》本文介绍了在JavaScript中将对象转换为数组的三种实用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录方法1:使用Object.keys()和Array.map()方法2:使用Object.entr

mybatis直接执行完整sql及踩坑解决

《mybatis直接执行完整sql及踩坑解决》MyBatis可通过select标签执行动态SQL,DQL用ListLinkedHashMap接收结果,DML用int处理,注意防御SQL注入,优先使用#... 目录myBATiFBNZQs直接执行完整sql及踩坑select语句采用count、insert、u

Java服务实现开启Debug远程调试

《Java服务实现开启Debug远程调试》文章介绍如何通过JVM参数开启Java服务远程调试,便于在线上排查问题,在IDEA中配置客户端连接,实现无需频繁部署的调试,提升效率... 目录一、背景二、相关图示说明三、具体操作步骤1、服务端配置2、客户端配置总结一、背景日常项目中,通常我们的代码都是部署到远程

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave

Java中实现对象的拷贝案例讲解

《Java中实现对象的拷贝案例讲解》Java对象拷贝分为浅拷贝(复制值及引用地址)和深拷贝(递归复制所有引用对象),常用方法包括Object.clone()、序列化及JSON转换,需处理循环引用问题,... 目录对象的拷贝简介浅拷贝和深拷贝浅拷贝深拷贝深拷贝和循环引用总结对象的拷贝简介对象的拷贝,把一个

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

创建springBoot模块没有目录结构的解决方案

《创建springBoot模块没有目录结构的解决方案》2023版IntelliJIDEA创建模块时可能出现目录结构识别错误,导致文件显示异常,解决方法为选择模块后点击确认,重新校准项目结构设置,确保源... 目录创建spChina编程ringBoot模块没有目录结构解决方案总结创建springBoot模块没有目录

javaSE类和对象进阶用法举例详解

《javaSE类和对象进阶用法举例详解》JavaSE的面向对象编程是软件开发中的基石,它通过类和对象的概念,实现了代码的模块化、可复用性和灵活性,:本文主要介绍javaSE类和对象进阶用法的相关资... 目录前言一、封装1.访问限定符2.包2.1包的概念2.2导入包2.3自定义包2.4常见的包二、stati