概述
通过上篇关于数组动态扩容导致频繁GC的文章假笨说-又抓了一个导致频繁GC的鬼--数组动态扩容大家或许GET到了这么一些点。
那是否还想过这么一些问题呢?
接下来主要围绕这两个问题展开,算是对上篇文章的一个补充
新数组在哪里分配
老实说,如果之前线上碰到的那个问题新数组是在老生代分配的话,那就不会有上篇文章,更不会有这篇文章,但是到底有没有可能在老生代分配呢?其实是有可能的。
上面的代码是慢速路径分配的代码,先判断是否应该到新生代分配
其中_pretenure_size_threshold_words的值是jvm参数PretenureSizeThreshold指定的,如果我们指定了这个值,那意味着如果我们单次要求分配的超过了这个值就想到老生代去分配,当然这个值默认是0,表示不会对对象的大小做check,都优先到新生代分配。
如果不到新生代分配,或者新生代分配不了,然后有判断是否会到老生代分配的条件。
所以新的数组分配还是有各种可能在老生代分配的,因为随着数组的不断扩容,数组也会变得越来越大,当大到某个程度,或者到上面的某个条件成立的时候,还是可能在老生代直接分配的。
那如果新数组是在老生代分配的话,那经过CMS GC就会将老生代里不可达的那个新数组给回收了,那就不存在新生代指向老生代的跨代引用,因而其实并不会发生这样的问题。
CMSScavengeBeforeRemark一定能触发YGC吗
CMSScavengeBeforeRemark这个参数本意是希望在CMS GC remark之前做一次YGC,正常情况下其实是会做一次YGC的,这个参数的好处是如果YGC比较有效果的话是能有效降低remark的时间长度,可以简单理解为如果大部分新生代的对象被回收了,那作为根的部分少了,从而提高了remark的效率。
但是,但是这个YGC一定会发生吗?下面对CMS GC remark之前你看到的现象分为三种情况:
对于看不到GC日志的情况,可以肯定是没有发生YGC,这种情况通过是因为上面提到的GC_locker导致的,有线程正在访问临界区的内存,访问这些内存的时候是不允许发生GC的,因为他们正在直接操作内存,而GC是会对对象做迁移的。另外你可能平时还会观察到一个非常奇怪的现象,偶尔你会看到有连续的两次YGC,其中后面那一次你会看到新生代使用的内存其实非常少但是也触发了一次YGC,其实就是因为GC_locker有补偿GC的逻辑。
对于第二种情况,你看到了YGC日志,同时也发现内存被回收了,这个毫无疑问,就是真的做了一次正常的YGC。
对于第三种情况,其实可能并没有做YGC,当然也不排除确实做了YGC,但是确实效果不好的情况,那什么情况下会不做YGC呢,我们看看下面在做YGC之前的代码。
如果这个判断成立,那就直接return了。
而collection_attempt_is_safe在ParNew下的实现如下
***一条相对比较关键,具体实现如下:
如果老生代可用的空间足以容得下之前的新生代平均晋升的size,或者容的下新生代现在使用的size,那说明是可以正常做YGC的,那接下来就会准备做YGC,但是如果上面的条件都不满足,那就会认为这次YGC做起来会没什么效果,或者比较危险,***不做,于是就会直接返回,但是这种情况下,YGC的日志还是照常会打的,你看到的现象就是YGC前后内存大小不变。
总结
还是总结下吧,针对动态数组扩容的问题,可以有两种情况
【本文是专栏作者李嘉鹏的原创文章,转载请通过微信公众号(你假笨,id:lovestblog)联系作者本人获取授权】
分享文章:关于数组动态扩容导致频繁GC的问题,我还有话说
链接地址:http://www.shufengxianlan.com/qtweb/news15/331915.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联