文档章节

没错,老板让我写个 BUG!

crossoverJie
 crossoverJie
发布于 2018/12/12 08:30
字数 1754
阅读 9345
收藏 113

前言

标题没有看错,真的是让我写个 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 对象。

但这里其实还有一个隐藏条件:那就是这个对象是局部变量。如果该对象是全局变量那依然不能被回收。

也就是我们常说的对象不可达,这样不可达的对象在 GC 发生时就会被认为是需要回收的对象从而进行回收。

在多考虑下,为什么有些人会认为方法执行完毕后局部变量会被回收呢?

我想这应当是记混了,其实方法执行完毕后回收的是栈帧

它最直接的结果就是导致 mem 这个对象没有被引用了。但没有引用并不代表会被马上回收,也就是上面说到的需要产生 GC 才会回收。

所以使用的是上面提到的对象不可达所采用的可达性分析算法来表明哪些对象需要被回收。

当对象没有被引用后也就认为不可达了。

这里有一张动图比较清晰:

当方法执行完之后其中的 mem 对象就相当于图中的 Object 5,所以在 GC 时候就会回收掉。

优先在 Eden 区分配对象

其实从上面的例子中可以看出对象是优先分配在新生代中 Eden 区的,但有个前提就是对象不能太大。

以前也写过相关的内容:

大对象直接进入老年代

而大对象则是直接分配到老年代中(至于多大算大,可以通过参数配置)。


当我直接分配 1000M 内存时,由于 Eden 区不能直接装下,所以改为分配在老年代中。

可以看到 Eden 区几乎没有变动,但是老年代却涨了 37% ,根据之前计算的老年代内存 2730M 算出来也差不多是 1000M 的内存。

Linux 内存查看

回到这次我需要完成的需求:增加服务器内存和 CPU 的消耗。

CPU 还好,本身就有一定的使用,同时每创建一个对象也会消耗一些 CPU。

主要是内存,先来看下没启动这个应用之前的内存情况。

大概只使用了 3G 的内存。

启动应用之后大概只消耗了 600M 左右的内存。

为了满足需求我需要分配一些内存,但这里有点需要讲究。

不能一直分配内存,这样会导致 CPU 负载太高了,同时内存也会由于 GC 回收导致占用也不是特别多。

所以我需要少量的分配,让大多数对象在新生代中,为了不被回收需要保持在百分之八九十。

同时也需要分配一些大对象到老年代中,也要保持老年代的使用在百分之八九十。

这样才能最大限度的利用这 4G 的堆内存。

于是我做了以下操作:

  • 先分配一些小对象在新生代中(800M)保持新生代在90%
  • 接着又分配了老年代内 *(100%-已使用的28%);也就是 2730*60%=1638M 让老年代也在 90% 左右。

效果如上。

最主要的是一次 GC 都没有发生这样也就达到了我的目的。

最终内存消耗了 3.5G 左右。

总结

虽说这次的需求是比较奇葩,但想要精确的控制 JVM 的内存分配还是没那么容易。

需要对它的内存布局,回收都要有一定的了解,写这个 Bug 的过程确实也加深了印象,如果对你有所帮助请不要吝啬你的点赞与分享。

你的点赞与分享是对我最大的支持

© 著作权归作者所有

共有 人打赏支持
crossoverJie
粉丝 627
博文 79
码字总数 149656
作品 0
江北
后端工程师
私信 提问
加载中

评论(37)

来自长者的爱
来自长者的爱

引用来自“leeyinghui1107”的评论

这么做产品,唉!
个人认为,程序员也好产品也好,追求的应该是更快、更小、更简洁易用。
遇到过很多类似的情况,明明一个树莓派就能搞定,cpu不会超过5%的需求,最后搞了个两台服务器,还美其名曰双机热备,还好没有把存储、数据都分离出去。
现在的各种数据中心,尤其是银行、政府部门,按照规定计算出来的负荷配置的UPS、空调,最后机柜满了以后才发现,总负载率很低,大部分服务器负载都是个位数级别的。
反正公司赚了钱、甲方达到了目的,个别人也因此获利,至于浪费,关大家屁事。

引用来自“crossoverJie”的评论

兄弟你想的有点多😅

引用来自“leeyinghui1107”的评论

不是想得多,其实这事儿还真是要有点原则性,就好比有些体育项目,输球出线才能避开强敌,有的人会去做,有的人会拒绝,我会选择拒绝。

引用来自“crossoverJie”的评论

这就拒绝了那社会可复杂多了。

况且这就是测试环境为了服务器不被回收而已,还让自己熟悉了 JVM 何乐而不为呢。

引用来自“leeyinghui1107”的评论

社会可以复杂,做人不能

引用来自“来自长者的爱”的评论

大佬我想问下,树莓派在我们的开发过程中,可以用在什么地方?对树莓派实在不了解,只觉得很吊的样子😂

引用来自“leeyinghui1107”的评论

谁也不是什么大佬,普通程序员而已。我用树莓派主要做一些硬件设备的数据采集,一般是通过串口服务器连接串口设备,或者通过tcp、snmp之类的接口。采集到的数据需要处理,存档。这样的应用,基本上用树莓派就可以胜任,甚至包括小规模的数据存储,都可以集成在树莓派里面。这货太便宜了,尤其适合这种io型的应用。
多谢。赶紧记小本本
外包项目发布平台00
程序员外包项目兼职平台,教你怎么年入500W!欢迎加入 www.hiyougo.cn
Iridium
Iridium
霍建奎也是这么想的,他在那次会议上多次说 I'm proud of my work.
即使不做这个需求,你还是可以得到 JVM 相关的知识的。技术为什么不是最重要的,这也有一个答案了。
l
leeyinghui1107

引用来自“leeyinghui1107”的评论

这么做产品,唉!
个人认为,程序员也好产品也好,追求的应该是更快、更小、更简洁易用。
遇到过很多类似的情况,明明一个树莓派就能搞定,cpu不会超过5%的需求,最后搞了个两台服务器,还美其名曰双机热备,还好没有把存储、数据都分离出去。
现在的各种数据中心,尤其是银行、政府部门,按照规定计算出来的负荷配置的UPS、空调,最后机柜满了以后才发现,总负载率很低,大部分服务器负载都是个位数级别的。
反正公司赚了钱、甲方达到了目的,个别人也因此获利,至于浪费,关大家屁事。

引用来自“crossoverJie”的评论

兄弟你想的有点多😅

引用来自“leeyinghui1107”的评论

不是想得多,其实这事儿还真是要有点原则性,就好比有些体育项目,输球出线才能避开强敌,有的人会去做,有的人会拒绝,我会选择拒绝。

引用来自“crossoverJie”的评论

这就拒绝了那社会可复杂多了。

况且这就是测试环境为了服务器不被回收而已,还让自己熟悉了 JVM 何乐而不为呢。

引用来自“leeyinghui1107”的评论

社会可以复杂,做人不能

引用来自“来自长者的爱”的评论

大佬我想问下,树莓派在我们的开发过程中,可以用在什么地方?对树莓派实在不了解,只觉得很吊的样子😂

引用来自“ansj”的评论

楼上的你让他们喷可以。让他们回答具体的问题。全部选择性失明。一个个牛逼的不行,处理具体问题就变成乌龟了。
乱给别人打标签不是个好习惯
l
leeyinghui1107

引用来自“leeyinghui1107”的评论

这么做产品,唉!
个人认为,程序员也好产品也好,追求的应该是更快、更小、更简洁易用。
遇到过很多类似的情况,明明一个树莓派就能搞定,cpu不会超过5%的需求,最后搞了个两台服务器,还美其名曰双机热备,还好没有把存储、数据都分离出去。
现在的各种数据中心,尤其是银行、政府部门,按照规定计算出来的负荷配置的UPS、空调,最后机柜满了以后才发现,总负载率很低,大部分服务器负载都是个位数级别的。
反正公司赚了钱、甲方达到了目的,个别人也因此获利,至于浪费,关大家屁事。

引用来自“crossoverJie”的评论

兄弟你想的有点多😅

引用来自“leeyinghui1107”的评论

不是想得多,其实这事儿还真是要有点原则性,就好比有些体育项目,输球出线才能避开强敌,有的人会去做,有的人会拒绝,我会选择拒绝。

引用来自“crossoverJie”的评论

这就拒绝了那社会可复杂多了。

况且这就是测试环境为了服务器不被回收而已,还让自己熟悉了 JVM 何乐而不为呢。

引用来自“leeyinghui1107”的评论

社会可以复杂,做人不能

引用来自“来自长者的爱”的评论

大佬我想问下,树莓派在我们的开发过程中,可以用在什么地方?对树莓派实在不了解,只觉得很吊的样子😂
谁也不是什么大佬,普通程序员而已。我用树莓派主要做一些硬件设备的数据采集,一般是通过串口服务器连接串口设备,或者通过tcp、snmp之类的接口。采集到的数据需要处理,存档。这样的应用,基本上用树莓派就可以胜任,甚至包括小规模的数据存储,都可以集成在树莓派里面。这货太便宜了,尤其适合这种io型的应用。
a
ansj

引用来自“leeyinghui1107”的评论

这么做产品,唉!
个人认为,程序员也好产品也好,追求的应该是更快、更小、更简洁易用。
遇到过很多类似的情况,明明一个树莓派就能搞定,cpu不会超过5%的需求,最后搞了个两台服务器,还美其名曰双机热备,还好没有把存储、数据都分离出去。
现在的各种数据中心,尤其是银行、政府部门,按照规定计算出来的负荷配置的UPS、空调,最后机柜满了以后才发现,总负载率很低,大部分服务器负载都是个位数级别的。
反正公司赚了钱、甲方达到了目的,个别人也因此获利,至于浪费,关大家屁事。

引用来自“crossoverJie”的评论

兄弟你想的有点多😅

引用来自“leeyinghui1107”的评论

不是想得多,其实这事儿还真是要有点原则性,就好比有些体育项目,输球出线才能避开强敌,有的人会去做,有的人会拒绝,我会选择拒绝。

引用来自“crossoverJie”的评论

这就拒绝了那社会可复杂多了。

况且这就是测试环境为了服务器不被回收而已,还让自己熟悉了 JVM 何乐而不为呢。

引用来自“leeyinghui1107”的评论

社会可以复杂,做人不能

引用来自“来自长者的爱”的评论

大佬我想问下,树莓派在我们的开发过程中,可以用在什么地方?对树莓派实在不了解,只觉得很吊的样子😂
楼上的你让他们喷可以。让他们回答具体的问题。全部选择性失明。一个个牛逼的不行,处理具体问题就变成乌龟了。
来自长者的爱
来自长者的爱

引用来自“leeyinghui1107”的评论

这么做产品,唉!
个人认为,程序员也好产品也好,追求的应该是更快、更小、更简洁易用。
遇到过很多类似的情况,明明一个树莓派就能搞定,cpu不会超过5%的需求,最后搞了个两台服务器,还美其名曰双机热备,还好没有把存储、数据都分离出去。
现在的各种数据中心,尤其是银行、政府部门,按照规定计算出来的负荷配置的UPS、空调,最后机柜满了以后才发现,总负载率很低,大部分服务器负载都是个位数级别的。
反正公司赚了钱、甲方达到了目的,个别人也因此获利,至于浪费,关大家屁事。

引用来自“crossoverJie”的评论

兄弟你想的有点多😅

引用来自“leeyinghui1107”的评论

不是想得多,其实这事儿还真是要有点原则性,就好比有些体育项目,输球出线才能避开强敌,有的人会去做,有的人会拒绝,我会选择拒绝。

引用来自“crossoverJie”的评论

这就拒绝了那社会可复杂多了。

况且这就是测试环境为了服务器不被回收而已,还让自己熟悉了 JVM 何乐而不为呢。

引用来自“leeyinghui1107”的评论

社会可以复杂,做人不能
大佬我想问下,树莓派在我们的开发过程中,可以用在什么地方?对树莓派实在不了解,只觉得很吊的样子😂
l
leeyinghui1107

引用来自“leeyinghui1107”的评论

这么做产品,唉!
个人认为,程序员也好产品也好,追求的应该是更快、更小、更简洁易用。
遇到过很多类似的情况,明明一个树莓派就能搞定,cpu不会超过5%的需求,最后搞了个两台服务器,还美其名曰双机热备,还好没有把存储、数据都分离出去。
现在的各种数据中心,尤其是银行、政府部门,按照规定计算出来的负荷配置的UPS、空调,最后机柜满了以后才发现,总负载率很低,大部分服务器负载都是个位数级别的。
反正公司赚了钱、甲方达到了目的,个别人也因此获利,至于浪费,关大家屁事。

引用来自“crossoverJie”的评论

兄弟你想的有点多😅

引用来自“leeyinghui1107”的评论

不是想得多,其实这事儿还真是要有点原则性,就好比有些体育项目,输球出线才能避开强敌,有的人会去做,有的人会拒绝,我会选择拒绝。

引用来自“crossoverJie”的评论

这就拒绝了那社会可复杂多了。

况且这就是测试环境为了服务器不被回收而已,还让自己熟悉了 JVM 何乐而不为呢。
社会可以复杂,做人不能
ylxs90
ylxs90

引用来自“freezingsky”的评论

你每次操作完之后 ,强制把byte对象 置成null, JVM GC的时候 ,会快一些.

引用来自“crossoverJie”的评论

目的并不是加快回收。

再说平时开发你真的会手动置为 null?

引用来自“freezingsky”的评论

平日开发,如果只是简单的byte数组,不会. 但比如用来作一些图片处理,就一定会!

引用来自“ylxs90”的评论

你们真的认为设置成null就会更容易被回收,或者回收更快一点?

引用来自“freezingsky”的评论

一,一文中,有讲到此事, 并对byte[]这一块的回收,为何不会在方法出栈后释放做了解释.
二, 阁下可以自己尝试一下.

引用来自“ylxs90”的评论

哪个文章里面有这种说法?说出来我见识见识!人会对不缺定的东西去验证真伪,但是对明显错的东西不会再去验证一下是不是有错。java class文件看过么?你来跟我说说把一个变量设置成null在字节码那里会调用什么指令?

引用来自“ylxs90”的评论

好吧,确实有一个设置成null的指令,我错了

引用来自“freezingsky”的评论

平日里比较忙,没来得及看回复. 我说的一文,指的是这本书,其中作者对byte[]置null与否做了解释和描述.大家有兴趣可以自己去看一下.
顺便说明一下,大多数情况下,我们都不会说特地对byte[]置null,当然也不会对其他对象手动置null,只是有些情况下, 做针对性的处理罢了.

引用来自“freezingsky”的评论

我晕,怪不得你们看不到我说的哪一本书,原来,评论里有自动 过滤功能. 只能提供书本链接了...https://item.jd.com/11252778.html?dist=jd
这本书我六年前就看过了,而且来来回回看了不下5遍,都没有说把一个对象设置成null会有意义,相反我在这本书里得到的观念就是,设置成null没有任何意义。这书里说的JVM的垃圾回收都不是靠引用计数的。都是靠着栈上回溯。那你设置成null有什么用呢? 唯一的可能就是在同样的作用域内堆空间已经不够用了,触发了full gc(或者执行了足够长的时间),然后检查到这个对象已经被设置成null了。然后这个对象被回收
f
freezingsky

引用来自“freezingsky”的评论

你每次操作完之后 ,强制把byte对象 置成null, JVM GC的时候 ,会快一些.

引用来自“crossoverJie”的评论

目的并不是加快回收。

再说平时开发你真的会手动置为 null?

引用来自“freezingsky”的评论

平日开发,如果只是简单的byte数组,不会. 但比如用来作一些图片处理,就一定会!

引用来自“ylxs90”的评论

你们真的认为设置成null就会更容易被回收,或者回收更快一点?

引用来自“freezingsky”的评论

一,一文中,有讲到此事, 并对byte[]这一块的回收,为何不会在方法出栈后释放做了解释.
二, 阁下可以自己尝试一下.

引用来自“ylxs90”的评论

哪个文章里面有这种说法?说出来我见识见识!人会对不缺定的东西去验证真伪,但是对明显错的东西不会再去验证一下是不是有错。java class文件看过么?你来跟我说说把一个变量设置成null在字节码那里会调用什么指令?

引用来自“ylxs90”的评论

好吧,确实有一个设置成null的指令,我错了

引用来自“freezingsky”的评论

平日里比较忙,没来得及看回复. 我说的一文,指的是这本书,其中作者对byte[]置null与否做了解释和描述.大家有兴趣可以自己去看一下.
顺便说明一下,大多数情况下,我们都不会说特地对byte[]置null,当然也不会对其他对象手动置null,只是有些情况下, 做针对性的处理罢了.
我晕,怪不得你们看不到我说的哪一本书,原来,评论里有自动 过滤功能. 只能提供书本链接了...https://item.jd.com/11252778.html?dist=jd
漫谈程序员系列:让程序员蛋疼的那些事儿

转自程序视界 听说嫁人要嫁程序员,钱多话少死得早。这话多半是程序员自己黑自己的。程序员是有非常特别的幽默感的一群,善于自嘲,勇于自黑,耐受力超强,很多事无可无不可,不到是不可孰不...

山里来的鱼
2015/07/24
0
0
程序员被老板要求两个月做个类似京东的app,困难就多加一个人 网友:辞职吧

隔行如隔山这句话说的真没错,尤其是现在的编程开发,如果你不是程序员的话,可能看程序员工作就是在电脑面前敲敲代码,觉得十分简单,不就是敲敲代码,这么简单的是谁不会呢,但是只有程序员...

IT智云编程
2018/11/05
0
0
开发人员的生活现实

这才是开发人员生活的真是写照……你中枪了咩?(多图,慎入) 当你向生产环境中上传东西的时候: 当你未使用Google进行搜索就找到问题解决方案的时候: 当你关掉IDE,却发现代码没有保存的时...

0x0bject
2015/02/09
2.6K
14
程序员最不想让你知道的尴尬瞬间,看完我眼睛都绿了

专栏 | 九章算法 网址 | www.jiuzhang.com编程可能是这世界上最难的工作之一了, 但同时, 也产生了一种快乐叫程序员式快乐。 细数程序员的那些逗比工作反应,没有什么是一个GIF解决不了的,...

九章算法
2018/09/28
0
0
我是一个程序员

转自: http://www.eoeandroid.com/thread-921665-1-1.html?_dsign=ae71de44 我叫张三,身高 1.9 米,不要看我身材高大,我的手可细的很。我敲键盘的速度可以达到 APM 666,不带一个按错的键。...

carlos
2016/05/19
3.2K
35

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周日乱弹 —— 没时间 没头发 但有钱

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @开源中国总经办主任 :分享齐一的单曲《这个年纪》 《这个年纪》- 齐一 手机党少年们想听歌,请使劲儿戳(这里) @肿肿卷 :我真的可以睡一天...

小小编辑
15分钟前
1
0
Django进阶 1.1 ORM基础—ORM 1.2.1 增删改查之查询 1.2.2 删改增 (1) 1.2.3 删改增 (2)

ORM基础 ORM是Django操作数据库的API,Django的作者将sql语句封装在里面供我们使用。 我们前面还提到过Django提供一个模拟数据库的工具,sqlite,供我们学习测试使用。 如果我们想使用mysql...

隐匿的蚂蚁
今天
1
0
Windows 上安装 Scala

在安装 Scala 之前需要先安装 Java 环境,具体安装的详细方法就不在这里描述了。 您可以自行搜索我们网站中的内容获得其他网站的帮助来获得如何安装 Java 环境的方法。 接下来,我们可以从 ...

honeymose
今天
3
0
数据库篇多表操作

第1章 多表操作 实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系...

stars永恒
今天
3
0
nginx日志自动切割

1.日志配置(Nginx 日志) access.log----记录哪些用户,哪些页面以及用户浏览器,IP等访问信息;error.log------记录服务器错误的日志 #配置日志存储路径:location / {      a...

em_aaron
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部