可以增加gc time引用了旧对象的短命对象吗? [英] Could increase gc time short lived object that has references to old lived object?
问题描述
我需要澄清一下次要gc集合的行为.如果它们在旧空间变大时表现最差
I need some clarification about how minor gc collections behave. calling a()
or calling b()
in a long-lived application, if they could behave worstly when old space gets bigger
//an example instance lives all application life cycle 24x7
public class Example {
private Object longLived = new Object();
public void a(){
var shortLived = new ShortLivedObject(longLived); // longLived now is attribute
shortLived.doSomething();
}
public void b(){
new ShortLivedObject().doSomething(new Object()); // actually now is shortlived
}
}
我的疑问来自哪里?我发现,在使用的使用权空间变大的应用程序中,gc暂停次数增加了.
Where does my doubt comes from? I found out that in an app in which the used tenured space gets bigger, there is an increase of minor gc pauses.
进行一些测试,我发现如果我强迫jvm使用选项a()
和另一个jvm使用选项b()
,则当旧空间变大时,带有选项b()
的jvm的暂停持续时间较短.但我不知道为什么.
Making some tests I found out that if I force the jvm to use option a()
and another jvm to use option b()
, then the jvm with option b()
has shorter pause duration time when the old space gets bigger but i can't figured out why.
我在4096中使用此属性 XX:ParGCCardsPerStrideChunk 在应用程序中解决了该问题,但我想知道上述情况是否会导致gctimes增大,从而导致gccard表中的扫描速度变慢或我不知道或根本不相关的东西.
I solved that issue in the app, using this property XX:ParGCCardsPerStrideChunk in 4096, but i want to know if situation which i described above can lead in increasing gctimes cause scanning in gccard tables is slower or something that i don't know or is not related at all.
推荐答案
免责声明:到目前为止,我还不是GC专家,但最近为了好玩而深入这些细节.
Disclaimer: I am by far no GC expert, but lately getting into these details for fun.
正如我在评论中所说,您正在使用一个已过时的收集器,没有人支持它,也没人愿意使用它,切换到G1
甚至更好的IMHO切换到Shenandoah
:从这个简单的开始首先.
As I said in the comments, you are using a collector that is deprecated, no one supports it and no one wants to use it, switch to G1
or even better IMHO switch to Shenandoah
: start from this simple thing first.
我只能假定您将其默认值增加了 ParGCCardsPerStrideChunk
,并且可能得到了一些ms
的帮助(尽管我们没有证明) .我们也没有来自GC,CPU活动,日志等的日志;因此,这很难回答.
I can only assume that you increased ParGCCardsPerStrideChunk
from its default value and that probably helped by a few ms
(though we have no proof of that). We also have no logs from GC, CPU activity, logs, etc; thus this is pretty complicated to answer.
如果确实有大堆(数十GB)和 年轻空间 ,则您有足够的GC线程,将该参数设置为更大的值可能确实有帮助,可能甚至与您提到的card table
有关.进一步阅读原因.
If indeed you have a big heap (tens of GB) and a big young space and you have enough GC Threads, setting that parameter to a bigger value might help indeed and it might even have to do with card table
that you are mentioning. Read further why.
CMS
将堆分为old space
和young space
,它可以选择任何其他区分符,但是他们选择了age
(就像G1
一样).为什么需要那?为了能够仅扫描和收集堆的部分区域(完全扫描它非常昂贵). young space
是在stop-the-world
暂停的情况下收集的,因此它最好变小,否则您将不满意.这就是为什么为什么您通常会看到与old ones
相比更多的young collections
.
CMS
splits the heap into old space
and young space
, it could have chosen any other discriminator, but they chose age
(just like G1
). Why is that needed? To be able to scan and collect only partial regions of the heap (scanning it entirely is very expensive). young space
is collected with a stop-the-world
pause, so it better be small, otherwise you will not be happy; that is why also why you usually will see many more young collections
compare to old ones
.
扫描young space
时唯一的问题是:如果从old space
引用到young space
的对象,会发生什么?收集这些显然是错误的,但是扫描整个old space
以找出答案将完全破坏generational collections
的目的.因此:card table
.
The only problem when you scan young space
is: what happens if there are references from old space
to objects from young space
? Collecting those is obviously wrong, but scanning the entire old space
to find out that answer would defeat the purpose of generational collections
entirely. Thus: card table
.
这会跟踪从old space
到young space
引用的引用,因此它知道什么是垃圾. G1
也使用card table
,但也添加了RememberedSet
(此处不做详细介绍).实际上,RememberedSets
实在是太庞大了,这就是G1
成为世代相传的原因. (仅供参考:Shenandoah
使用matrix
而不是card table
-使其成为 not 世代的.)
This keeps track of reference from old space
to young space
references, so it knows what exactly is garbage or not. G1
uses a card table
too, but also adds a RememberedSet
(not going into the details here). In practice, RememberedSets
turned out to be HUGE, that is why G1
became generational. (FYI: Shenandoah
uses matrix
instead of card table
- making it not generational).
因此,这个巨大的介绍旨在表明确实增加了ParGCCardsPerStrideChunk
可能有所帮助.您正在为每个GC线程分配更多的空间来进行处理.默认值为256
,卡表为512 bytes
,表示
So this huge intro, was to show that indeed increasing ParGCCardsPerStrideChunk
might have helped. You are giving each GC thread more space to work on. The default value is 256
and card table is 512 bytes
, that means
256 * 512 = 128KB per stride of old generation
例如,如果您有一个32 GB
堆,那是多少个数十万步幅?可能太多了.
If you for example have a heap of 32 GB
how many hundreds of thousands of strides is that? Probably too many.
现在,为什么还要在这里进行讨论?我不知道.
Now, why you also bring reference counting
into the discussion here? I have no idea.
您显示的示例具有不同的语义,因此很难推理;不过,我仍然会尝试.您必须了解对象的 reachability 只是从某些根(称为GC roots
)开始的图.首先让我们看这个例子:
The examples that you have shown have different semantics and as such are kind of difficult to reason about; I'll still try to, though. You have to understand that reachability of Objects is just a graph that starts from some roots (called GC roots
). Let's take this example first:
public void b(){
new ShortLivedObject().doSomething(new Object()); // actually now is shortlived
}
一旦完成doSomething
方法调用并且其 scope 仅在该方法之内,
ShortLivedObject
实例就会被忘记".因此,其余部分与doSomething
:new Object
的参数有关.如果doSomething
对其获得的参数不做任何操作(通过GC root
图使其可访问),则在完成doSomething
之后,它也将有资格使用GC.但是,即使doSomething
使new Object
可以访问,也仍然意味着ShortLivedObject
实例有资格使用GC.
ShortLivedObject
instance is "forgotten" as soon as doSomething
method invocation is done and its scope is within the method only, as such no one can reach it. Thus the remaining part is about the parameter of doSomething
: new Object
. If doSomething
does not do anything fishy with the parameter it got (making it reachable via a GC root
graph), then after doSomething
is done, it would become eligible for GC too. But even if doSomething
makes new Object
reachable it still means that ShortLivedObject
instance is eligible for GC.
这样,即使Example
可以访问(意味着无法收集),也可能会收集ShortLivedObject
和new Object()
.看起来可能像这样:
As such, even if Example
is reachable (means it can't be collected), ShortLivedObject
and new Object()
can potentially be collected. It can look like this:
new Object()
|
\ /
ShortLivedObject
|
\ /
GC Root -> ... - > Example
您会看到,一旦GC
将扫描Example
实例,它可能根本不会 扫描ShortLivedObject
(这就是为什么垃圾被识别为与 live 对象相反).因此,GC算法将简单地丢弃整个图形,而根本不扫描它.
You can see that once GC
will scan Example
instance, it might not scan ShortLivedObject
at all (that is why garbage is identified as the opposite of live objects). So a GC algorithm will simply discard the entire graph and not scan it at all.
第二个示例不同:
public void a(){
var shortLived = new ShortLivedObject(longLived);
shortLived.doSomething();
}
区别在于longLived
这是一个 instance 字段,因此该图看起来会有所不同:
The difference is that longLived
here is an instance field and, as such, the graph will look a bit different:
ShortLivedObject
|
\ /
longLived
/ \
|
GC Root -> ... - > Example
很明显,在这种情况下可以收集ShortLivedObject
,但是 longLived
可以收集.
It's obvious that ShortLivedObject
can be collected in this case, but not longLived
.
您必须了解,如果可以收集Example
实例,那么这根本不重要;该图将不会被遍历,并且可以收集Example
使用的所有内容.
What you have to understand that this does not matter at all, if Example
instance can be collected; this graph will not be traversed and everything that Example
uses can be collected.
您现在应该可以了解,使用方法a
可以保留更多的垃圾,并且可以将其潜在地移动到old space
(当它们足够老时)和 can 可能会使您的young pauses
更长,确实增加了ParGCCardsPerStrideChunk
力量的帮助;但这是高度推测性的,您将需要一种非常糟糕的相同分配模式来完成所有这些工作.没有日志,我高度对此表示怀疑.
You should be able to understand now that using method a
can retain a bit more garbage and can potentially move it to old space
(when they become old enough) and can potentially make your young pauses
be longer and indeed increasing ParGCCardsPerStrideChunk
might help a bit; but this is highly speculative and you would need a pretty bad same pattern of allocations to happen for all of this to happen. Without logs, I highly doubt that.
这篇关于可以增加gc time引用了旧对象的短命对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!