老年代碎片化问题. java5的改进.

总结:

java 5的改进就是 老年代不需要连续的整块空间来容纳被晋升的新生代[ 新生代多少,老年代就要准备多少]

所以比例就是:1:2

新生代与老年代的比例,如 –XX:NewRatio=2,则新生代占整个堆空间的1/3,老年代占2/3

不等于一个足够大的坑。

我曾今提到过,低暂停垃圾收集器为老年代维护了一个空余可用列表
,这些碎片可能成为一个问题. 如果你使用低暂停收集器,
只要几天甚至几天,就有一个巨大的(相对来说)的停顿,
原因就是老年代的碎片块。

在1.4.2及以上的版本中,为了做新生代的回收
有一个要求有一个连续的块
老年代的自由空间足够大
所有的新生代在GC调优文档中

http://java.sun.com/docs/hotspot/

这被称为新生代的保证。基本上
在新生代的回收中,任何可能存在的数据可能必须是
晋升到老年代,我们只是不知道会有多少
生存。作为我们通常保守的自我,我们假设所有这一切都会生存下去
所以在所有这一切都需要在老年代的空间。这是怎么回事
造成大停顿?如果新生代充满,需要收集
老年代没有足够的空间,然后全面收集
无论是新生代还是后代,都已经完成了。和这个收集
是一个停止的世界收集,而不是并发收集,所以你一般看到一个
暂停比你想要的要长得多。顺便说一句
收集也是一个压缩的收集,所以没有分裂
完整的回收结束。

在5.0中,我们添加了低暂停收集器的能力来开始一个新生代收集,并且老年代的空间不够的情况下回退垃圾回收。能够回退新生代
收集的功能需要我们进行一些改变。
我们现在保持平均的空间
这是用于晋升和使用(有一些适当的
填充在安全的程度)作为空间的要求
在老年代需要。此外,我们不再需要
一个连续的空间大块晋升,所以我们通过
老年代的自由空间量总数决定是否可以
做一个新生代的回收。不必拥有一个连续的空间来支持
晋升活动是碎片化的地方(或者是不经常出现的地方)。
有时使用
已晋升的平均值和老年代的空闲总数,虚拟机觉得
可以做一个新生代的回收,事实可能老年代的空间真的还不够
。在这种情况下,我们必须退出
新生代回收。退出收集很贵,但它是可行的。
这是一个很长的路要走,碎片化程度不大
一个问题. 在5.0,它仍然发生,但我们有更好的方式处理他。

如果遇到分裂问题,该怎么办?

尝试5.0。

或者您可以尝试更大的总堆和/或较小的新生代。
如果你的应用程序在边缘,它可能会给你足够的
额外的空间,以适应您的所有实时数据。但通常它只是延迟了这个问题。

或者您可以尝试使您的应用程序做一个完整的,压缩的收集
在一个不会打扰你的用户的时候。
如果你的应用程序可以去一天没有碰到
碎片问题,尝试在中间的System.gc()
晚。这将压缩堆,你可以希望去
另一天没有打破分裂问题。对没有逻辑“半夜”的应用程序这显然没有帮助



或者如果偶然最多
在您的应用程序中读取老年代中的数据
首先启动,您可以在完成后执行System.gc()
初始化,这可能有助于压缩所有数据
一个离开剩下的老年代的单一块
可用于晋升。取决于碎片模式
的应用程序,这可能是足够的。

或者你可能想要启动
并发收集较早。低暂停收集器尝试启动并发
收集即时(有一些安全因素)收集
老年代在它满了之前。如果你正在做并发
收集和释放足够的空间,您可以尽快尝试启动并发收集
它在碎片成为问题之前完成。
并发收集不执行压缩,但它们会执行
相邻的自由块如此大块的空闲空间
可以由并发收集产生。
启动并发收集的其中一个触发器是金额
在老年代的自由空间。
您可以导致并发收集
通过设置早点发生
选项-XX:CMSInitiatingOccupancyFraction =其中NNN是
正在使用的老年代的百分比超过这一比例
并发收集开始。这将增加您花费的总时间
做    
       
doesn't equal a big enough hole.

Did I mention that the low pause collector maintains free lists
for the space available in the tenured generation and
that fragmentation can become a problem? If you're using the low pause collector and things are
going just peachy for days and days and then there is a huge (relatively speaking) pause,
the cause may be fragmentation in the tenured generation.

In 1.4.2 and older releases in order to do a young generation collection
there was a requirement that there be a contiguous chunk of
free space in the tenured generation that was big enough to hold
all the the young generation. In the GC tuning documents at

http://java.sun.com/docs/hotspot/

this is referred to as the young generation guarantee. Basically
during a young generation collection, any data that survives may have to be
promoted into the tenured generation and we just don't know how much is going to
survive. Being our usual conservative selves we assumed all of it would survive and
so there needed to be room in the tenured generation for all of it. How does this
cause a big pause? If the young generation is full and needs to be collected but
there is not enough room in the tenured generation, then a full collection of
both the young generation and the tenured generations are done. And this collection
is a stop-the-world collection not a concurrent collection so you generally see a
pause much longer than you want to. By the way this full
collection is also a compacting collection so there is no fragmentation at the
end of the full collection.

In 5.0 we added the ability in the low pause collector to start a young
generation collection and then to back out of it if there was not enough
space in the tenured generation. Being able to backout of a young generation
collection allowed us to make a couple of changes.
We now keep an average of the amount of space
that is used for promotions and use that (with some appropriate
padding to be on the safe side) as the requirement for the space
needed in the tenured generation. Additionally we no longer need
a single contiguous chunk of space for the promotions so we look at the total
amount of free space in the tenured generation in deciding if we can
do a young generation collection. Not having to have a single contiguous chunk of space to support
promotions is where fragmentation comes in (or rather where it doesn't come in as often).
Yes, sometimes using the averages for the
amount promoted and the total amount of free in the tenured generation tells us to
go ahead and do a young generation collection and we get surprised (there really isn't enough
space in tenured generation). In that situation we have to back out of the
young generation collection. It's expensive to back out of a collection, but it's doable.
That's a very long way of saying that fragmentation is less of
a problem in 5.0. It still occurs, but we have better ways of dealling with it.

What should you do if you run into a fragmentation problem?

Try 5.0.

Or you could try a larger total heap and/or smaller young generation.
If your application is on the edge, it might give you just enough
extra space to fit all your live data. But often it just delays the problem.

Or you can try to make you application do a full, compacting collection
at a time which will not disturb your users.
If your application can go for a day without hitting a
fragmentation problem, try a System.gc() in the middle of the
night. That will compact the heap and you can hopefully go
another day without hitting the fragmentation problem. Clearly no help for an
application that does not have a logical "middle of the night".


Or if by chance most
of the data in the tenured generation is read in when your application
first starts up and you can do a System.gc() after you complete
initialization, that might help by compacting all data into
a single chunk leaving the rest of the tenured generation
available for promotions. Depending on the allocation pattern
of the application, that might be adequate.

Or you might want to start the
concurrent collections earlier. The low pause collector tries to start a concurrent
collection just in time (with some safety factor) to collect the
tenured generation before it is full. If you are doing concurrent
collections and freeing enough space, you can try starting a concurrent collection sooner so that
it finishes before the fragmentation becomes a problem.
The concurrent collections don't do a compaction, but they do
coalese adjacent free blocks so larger chunks of free space
can result from a concurrent collection.
One of the triggers for starting a concurrent collection is the amount
of free space in the tenured generation.
You can cause a concurrent collection to
occur early by setting the
option -XX:CMSInitiatingOccupancyFraction= where NNN is the
percentage of the tenured generation that is in use above which a
concurrent collection is started. This will increase the overall time you spend
doing GC but may avoid the fragmentation problem. And this will be more
effective with 5.0 because a single contiguous chunk of space is not required
for promotions.

By the way, I've increased the comment period for my blogs. I hadn't realized it was so short.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值