java 缩小幸存者空间导致持续的 full GC
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1271376/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Shrinking survivor spaces lead to continuous full GC
提问by Robert Munteanu
I've had this troubling experience with a Tomcat server, which runs:
我在 Tomcat 服务器上有过这种令人不安的经历,它运行:
- our Hudsonserver;
- a staging version of our web application, redeployed 5-8 times per day.
- 我们的哈德逊服务器;
- 我们的 Web 应用程序的临时版本,每天重新部署 5-8 次。
The problem is that we end up with continuous garbage collection, but the old generation is nowhere near to being filled. I've noticed that the survivor spaces are next to inexisting, and the garbage collector output is similar to:
问题是我们最终会持续进行垃圾回收,但是老年代还远没有被填满。我注意到幸存者空间几乎不存在,垃圾收集器输出类似于:
[GC 103688K->103688K(3140544K), 0.0226020 secs]
[Full GC 103688K->103677K(3140544K), 1.7742510 secs]
[GC 103677K->103677K(3140544K), 0.0228900 secs]
[Full GC 103677K->103677K(3140544K), 1.7771920 secs]
[GC 103677K->103677K(3143040K), 0.0216210 secs]
[Full GC 103677K->103677K(3143040K), 1.7717220 secs]
[GC 103679K->103677K(3143040K), 0.0219180 secs]
[Full GC 103677K->103677K(3143040K), 1.7685010 secs]
[GC 103677K->103677K(3145408K), 0.0189870 secs]
[Full GC 103677K->103676K(3145408K), 1.7735280 secs]
The heap information before restarting Tomcat is:
Tomcat重启前的heap信息为:
Attaching to process ID 10171, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 14.1-b02
using thread-local object allocation.
Parallel GC with 8 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 3221225472 (3072.0MB)
NewSize = 2686976 (2.5625MB)
MaxNewSize = 17592186044415 MB
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 21757952 (20.75MB)
MaxPermSize = 268435456 (256.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 1073479680 (1023.75MB)
used = 0 (0.0MB)
free = 1073479680 (1023.75MB)
0.0% used
From Space:
capacity = 131072 (0.125MB)
used = 0 (0.0MB)
free = 131072 (0.125MB)
0.0% used
To Space:
capacity = 131072 (0.125MB)
used = 0 (0.0MB)
free = 131072 (0.125MB)
0.0% used
PS Old Generation
capacity = 2147483648 (2048.0MB)
used = 106164824 (101.24666595458984MB)
free = 2041318824 (1946.7533340454102MB)
4.943684861063957% used
PS Perm Generation
capacity = 268435456 (256.0MB)
used = 268435272 (255.99982452392578MB)
free = 184 (1.7547607421875E-4MB)
99.99993145465851% used
The relevant JVM flags passed to Tomcat are:
传递给 Tomcat 的相关 JVM 标志是:
-verbose:gc -Dsun.rmi.dgc.client.gcInterval=0x7FFFFFFFFFFFFFFE -Xmx3g -XX:MaxPermSize=256m
Please note that the survivor spaces are sized at about 40 MB at startup.
请注意,启动时幸存者空间的大小约为 40 MB。
How can I avoid this problem?
我怎样才能避免这个问题?
Updates:
更新:
The JVM version is
JVM 版本是
$ java -version
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03)
Java HotSpot(TM) 64-Bit Server VM (build 14.1-b02, mixed mode)
I'm going to look into bumping up the PermGensize and seeing if that helps - probably the sizing of the survivor spaces was unrelated.
我将研究增加PermGen大小,看看是否有帮助 - 幸存者空间的大小可能无关。
回答by Aaron Digulla
The key is probably PS Perm Generationwhich is at 99.999% (only 184 bytesout of 256***MB*** free).
关键可能PS Perm Generation是 99.999%(256***MB*** 中只有 184个字节可用)。
Usually, I'd suggest that you give it more perm gen but you already gave it 256MB which should be plenty. My guess is that you have a memory leak in some code generation library. Perm Gen is mostly used for bytecode for classes.
通常,我建议你给它更多的 perm gen,但你已经给了它 256MB,这应该足够了。我的猜测是您在某些代码生成库中存在内存泄漏。Perm Gen 主要用于类的字节码。
回答by Michael Borgwardt
It's very easy to have ClassLoader leaks - all it takes is a single object loaded through the ClassLoader being referred by an object not loaded by it. A constantly redeployed app will then quickly fill PermGenSpace.
ClassLoader 很容易泄漏——它所需要的只是通过 ClassLoader 加载的单个对象被一个未由它加载的对象引用。一个不断重新部署的应用程序将很快填满 PermGenSpace。
This articleexplains what to look out for, and a followupdescribes how to diagnose and fix the problem.
回答by Hyman Leow
I think this is not that uncommon for an application server that gets continuously deployed to. The perm gen space, which is full for you, is where classes go. Keep in mind that JSPs are compiled as Java classes, and when you change a JSP, a new class gets generated and loaded.
我认为这对于持续部署到的应用程序服务器来说并不少见。烫发空间,对你来说已经满了,是上课的地方。请记住,JSP 被编译为 Java 类,当您更改 JSP 时,会生成并加载一个新类。
We have had this problem, and our solution is to have the app server restart occasionally.
我们遇到了这个问题,我们的解决方案是让应用服务器偶尔重启。
This is what I'd do:
这就是我要做的:
- Deploy Hudson to a separate server from your staging server
- Configure Hudson to restart your staging server from time to time. You can either do this one of two ways:
- Restart periodically (e.g., every night at midnight, regardless of if there's build activity); or
- Have the web app deployment job trigger the server restart job. If you do this make sure there's a really long quiet period for the restart job (we set ours to 2 hours), so that you don't get a server restart for every build (i.e., if two web app deployments happen within 2 hours, they'll only trigger one server restart).
- 将 Hudson 部署到与临时服务器不同的服务器
- 将 Hudson 配置为不时重新启动临时服务器。您可以通过以下两种方式之一执行此操作:
- 定期重启(例如,每晚午夜,无论是否有构建活动);或者
- 让 Web 应用程序部署作业触发服务器重启作业。如果您这样做,请确保重启工作有一个非常长的安静期(我们将我们的设置为 2 小时),这样您就不会在每次构建时重启服务器(即,如果两个 Web 应用程序部署在 2 小时内发生) ,它们只会触发一台服务器重启)。
回答by kdgregory
The flag -XX:SurvivorRatiosets the ratio between Eden and the survivor spaces. According to the JDK 1.5 tuning doc, the default value is 32, which gives a 1:32 ratio. This is in accordance with what you're seeing. It seems incredibly small to me, although I understand that only a very small number of objects are expected to make their way from Eden to the survivor space.
该标志-XX:SurvivorRatio设置了伊甸园和幸存者空间之间的比例。根据JDK 1.5 调优文档,默认值为 32,比例为 1:32。这与你所看到的一致。对我来说,它看起来非常小,尽管我知道只有极少数的物体会从伊甸园到达幸存者空间。
So, assuming that you have a lot of long-lived objects, you should decrease the survivor ratio. The risk is that you only have those long-lived objects during a startup phase, and so are limiting the Eden size. For a testing server, I doubt this is going to be an issue.
所以,假设你有很多长寿命的对象,你应该降低存活率。风险在于您在启动阶段只有那些长期存在的对象,因此会限制 Eden 的大小。对于测试服务器,我怀疑这会成为一个问题。
I'd probably also reduce the size of the Eden space, by increasing -XX:NewRatio(the default is 3). My gut says that a hundred MB or so is sufficient for the young generation, and you'll just be increasing the cost of garbage collection to have such a large amount of space allocated (ie, object will live in Eden far too long). But that's just instinct, and should definitely be validated for your environment.
我可能还会通过增加-XX:NewRatio(默认值为 3)来减小 Eden 空间的大小。我的直觉说一百MB左右对于年轻代来说就足够了,而且你只会增加垃圾收集的成本来分配如此大量的空间(即对象将在Eden中存活太久)。但这只是本能,绝对应该针对您的环境进行验证。
And a semi-related comment, after reading other replies: if you're not seeing errors for running out of permgen space, don't spend your time fiddling with it. The permgen is managed separately from the rest of the heap.
在阅读其他回复后,还有一条半相关的评论:如果您没有看到 permgen 空间用完的错误,请不要花时间摆弄它。permgen 与堆的其余部分分开管理。

