涨姿势的Jvm内存区域分配

1,230 阅读3分钟

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。

1 前言

由于对JVM比较有兴趣,机缘巧合看到了前阿里JVM团队某位大佬的博客。巧的是之前还投过这位大佬创立的技术公司。

大佬的博客里其中有一篇文章对于JVM对象分配提出了一个问题,有兴趣的朋友往下看,涨涨知识!

2 问题简介

image.png 在某次发生GC发生后,from space的利用率为12%,但是在下一次YGC准备发生的时候,发现from space的利用率变成了99%。

看到这里,请思考一会,不知道大家对这有什么想法。这边摘抄大佬的评价:

  • 回答一:如果你觉得这个现象不正常,说明你对JVM内存分析有一定的理解,但还是没有完全理解。
  • 回答二:如果你觉得这个现象没问题,绝大部分说明你对JVM内存分配还不够熟悉,极少部分情况说明你对它已经非常熟悉了,对它实现上的优缺点都了如指掌了。

3 原理分析

这边默认大家都了解过CMS的新生代和老年代,以及新生代GC的复制算法

在JVM中,堆主要由新生代和老生代组成,而新生代又分别由eden+s0(from space)+s1(to space)构成,通常情况下s0或者s1必定有一块是空的,主要用来做GC copy。

当我们创建一个正常对象的时候(ps:不是特别大),会申请分配一块内存。这块内存主要在新生代的eden区里分配。当然某些特殊情况可以直接到老生代去分配。

按照这种规则,正常情况下怎么也轮不到from space去分配内存,因此在上次GC完之后到下次GC之前不可能去from space分配内存。

车辙也找了下身边校招的小伙伴,刚出校园理论知识还忘的不多😂。他的回答也是没啥问题,你的答案呢?

4 模拟GC

这边我们来模拟下正常情况下和异常情况GC,然后通过GC信息和堆信息查看结果。

4.1 JVM配置

-Xms1024m
-Xmx1024m
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC

4.2 正常GC

image.png image.png

image.png 首先我们循环创建BigData对象,从而触发YoungGC,可以看到Before GC前from space的空间并没有变化。所以正常情况下,from space的空间是不会变化的。

回答二的朋友去自罚三杯🍺🍺

4.3 异常GC

  1. 通过上一期GC日志讲的OOM代码,触发CMS GC image.png

  2. 触发young gc,可以看到from space的空间在GC前同样分配了对象 image.png

image.png

4.4. 分配原因

按照大佬的解释是jvm的一个bug,咱也不敢问🤣🤣,实在有兴趣的朋友可以通过参考文章去看下~

5 结尾

这边简单介绍了JVM内存分配 复制算法的问题,如果有看不明白的同学建议去补下课,哈哈。

6 参考文章

假笨说-来一道PerfMa面试必考的GC题(肯定涨姿势)