没错,老板让我写个 BUG!

 

前言

标题没有看错,真的是让我写个 bug

刚接到这个需求时我内心没有丝毫波澜,甚至还有点激动。这可是我特长啊;终于可以光明正大的写 bug 了🙄。

先来看看具体是要干啥吧,其实主要就是要让一些负载很低的服务器额外消耗一些内存、CPU 等资源(至于背景就不多说了),让它的负载可以提高一些。

JVM 内存分配回顾

于是我刷刷一把梭的就把代码写好了,大概如下:

写完之后我就在想一个问题,代码中的 mem 对象在方法执行完之后会不会被立即回收呢?我想肯定会有一部分人认为就是在方法执行完之后回收。

我也正儿八经的去调研了下,问了一些朋友;果不其然确实有一部分认为是在方法执行完毕之后回收。

那事实情况如何呢?我做了一个试验。

我用以下的启动参数将刚才这个应用启动起来。

java -Djava.rmi.server.hostname=10.xx.xx.xx  -Djava.security.policy=jstatd.all.policy  -Dcom.sun.management.jmxremote.authenticate=false  -Dcom.sun.management.jmxremote.ssl=false  -Dcom.sun.management.jmxremote.port=8888   -Xms4g -Xmx4g  -jar bug-0.0.1-SNAPSHOT.jar

这样我就可以通过 JMX 端口远程连接到这个应用观察内存、GC 情况了。


如果是方法执行完毕就回收 mem对象,当我分配 250M 内存时;内存就会有一个明显的曲线,同时 GC 也会执行。


这时观察内存曲线。

会发现确实有明显的涨幅,但是之后并没有立即回收,而是一直保持在这个水位。同时左边的 GC 也没有任何的反应。

用 jstat 查看内存布局也是同样的情况。

不管是 YGC,FGC 都没有,只是 Eden 区的使用占比有所增加,毕竟分配了 250M 内存嘛。

那怎样才会回收呢?

我再次分配了两个 250M 之后观察内存曲线。

发现第三个 250M 的时候 Eden区达到了 98.83% 于是再次分配时就需要回收 Eden 区产生了 YGC

同时内存曲线也得到了下降。

整个的换算过程如图:

由于初始化的堆内存为 4G,所以算出来的 Eden 区大概为 1092M内存。

加上应用启动 Spring 之类消耗的大约 20% 内存,所以分配 3 次 250M 内存就会导致 YGC

再来回顾下刚才的问题:

mem 对象既然在方法执行完毕后不会回收,那什么时候回收呢。

其实只要记住一点即可:对象都需要垃圾回收器发生 GC 时才能回收;不管这个对象是局部变量还是全局变量。

通过刚才的实验也发现了,当 Eden 区空间不足产生 YGC 时才会回收掉我们创建的 mem 对象。

但这里其实还有一个隐藏条件:那就是这个对象是局部变量

50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信