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

相关文章

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

Java将时间戳转换为Date对象的方法小结

《Java将时间戳转换为Date对象的方法小结》在Java编程中,处理日期和时间是一个常见需求,特别是在处理网络通信或者数据库操作时,本文主要为大家整理了Java中将时间戳转换为Date对象的方法... 目录1. 理解时间戳2. Date 类的构造函数3. 转换示例4. 处理可能的异常5. 考虑时区问题6.

豆包 MarsCode 不允许你还没有女朋友

在这个喧嚣的世界里,爱意需要被温柔地唤醒。为心爱的她制作每日一句小工具,就像是一场永不落幕的浪漫仪式,每天都在她的心田播撒爱的种子,让她的每一天都充满甜蜜与期待。 背景 在这个瞬息万变的时代,我们都在寻找那些能让我们慢下来,感受生活美好的瞬间。为了让这份浪漫持久而深刻,我们决定为女朋友定制一个每日一句小工具。这个工具会在她意想不到的时刻,为她呈现一句充满爱意的话语,让她的每一天都充满惊喜和感动

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。