我们已经让我们的glassfish实例每两周下降一段时间java.lang.OutOfMemoryError: PermGen space.我将PermGen空间增加到512MB,并将startet转储内存使用量jstat -gc.两周后,我想出了下图,显示了PermGen空间是如何稳定增加的(x轴上的单位是分钟,y轴是KB).

我试着用谷歌搜索某种可以查明错误的分析工具,并在SO上提到一个线程提到jmap,这被证明是非常有帮助的.在倾倒的大约14000行中jmap -permstats $PID,大约包含12500行groovy/lang/GroovyClassLoader$InnerLoader,指向我们自己的Groovy代码或Groovy本身的某种内存泄漏.我必须指出,Groovy构造的相关代码库不到1%.
示例输出如下:
class_loader classes bytes parent_loader alive? type
<bootstrap> 3811 14830264 null live <internal>
0x00007f3aa7e19d20 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa7c850d0 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa5d15128 21 181072 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aad0b40e8 36 189816 0x00007f3a9d31fbf8 dead org/apache/jasper/servlet/JasperLoader@0x00007f3a7d0caf00
....
Run Code Online (Sandbox Code Playgroud)
那么我该如何进一步了解导致此问题的代码呢?
在本文中,我推断我们的Groovy代码是在某处动态创建类.从jmap的转储我可以看到大多数死对象/类(?)都有相同的parent_loader,虽然我不确定这在这个上下文中意味着什么.我不知道怎么从这里开始.
对于后来者来说,值得指出的是,接受的答案并不能解决问题.它只是通过不存储如此多的类信息来延长重启前所需的时间十倍.实际修复我们问题的是摆脱生成它的代码.我们使用验证(按合同设计)框架OVal,其中可以使用Groovy编写自定义约束作为方法和类的注释.在普通Java中删除注释以支持显式的前置条件和后置条件是很无聊的,但它完成了工作.我怀疑每次检查OVal约束时都会创建一个新的匿名类,并且关联的类数据以某种方式导致内存泄漏.
我在Tomcat应用程序上工作,该应用程序使用CMS收集器和内存条来触发GC.当我重新加载webapps时,我有时会遇到Old gen足以触发GC的情况,但死亡的类加载器不会被收集.
我读到类被分配到perm gen并且猜测它们因此被Old gen集合忽略.我写了下面的测试类来测试这个理论.
package test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
/*
JVM Options:
-server -XX:+UseMembar -XX:+UseConcMarkSweepGC
-XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=80
-XX:+UseCMSInitiatingOccupancyOnly -Xms100m -Xmx100m
-XX:PermSize=100m -XX:NewSize=10m -XX:MaxNewSize=10m
-verbose:gc -Xloggc:gc.log -XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
*/
public class ClassLoaderTest extends ClassLoader
{
@Override
protected synchronized Class<?> loadClass(String xiName, boolean xiResolve)
throws ClassNotFoundException
{
if (xiName.equals("test"))
{
// When asked to load "test", load Example.class
Class<?> c = Example.class;
String className = c.getName();
String classAsPath = className.replace('.', '/') + ".class";
InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath);
byte[] …Run Code Online (Sandbox Code Playgroud) 我正在使用JUnit,PowerMock和Mockito进行一些单元测试.我有很多测试类注释@RunWith(PowerMockRunner.class)和@PrepareForTest(SomeClassesNames)模拟最终类和200多个测试用例.
最近,当我在Eclipse或Maven2中运行我的整个测试套件时,我遇到了PermGen空间溢出的问题.当我逐个运行我的测试时,他们每个都成功.
我做了一些关于这方面的研究,但没有一个建议对我有帮助(我增加了PermGenSize和MaxPermSize).最近我发现有一个类只包含静态方法,每个方法返回用PowerMockito模拟的对象.我想知道这是否是一个好习惯,也许这是问题的根源,因为静态变量是在单元测试之间共享的?
一般来说,拥有一个带有许多返回静态模拟对象的静态方法的静态类是一个好习惯吗?
我正在编写一个Codec来处理使用定制有线协议通过TCP发送的消息.在解码过程中,我创建了许多Strings,BigDecimals和日期.客户端 - 服务器访问模式意味着客户端发出请求然后解码数千个响应消息是常见的,这会导致大量的重复 String s,BigDecimals等.
因此我创建了一个InternPool<T>允许我实习每类对象的类.在内部,池使用a WeakHashMap<T, WeakReference<T>>.例如:
InternPool<BigDecimal> pool = new InternPool<BigDecimal>();
...
// Read BigDecimal from in buffer and then intern.
BigDecimal quantity = pool.intern(readBigDecimal(in));
Run Code Online (Sandbox Code Playgroud)
我的问题:我使用InternPool的BigDecimal,但我应该还可以考虑使用它String 来代替 String的intern()方法,我相信使用的PermGen空间?使用PermGen空间有什么好处?
内部类比普通类更轻量级,还是最终java像普通类一样编译内部类?
我知道在java类不都是非常轻巧自己,他们占据了PermGen的内存的一部分,所以我想知道这是否是最好用的类似于闭包功能的内部类,或者如果标准类也做得很好?
我已经看到关于这个问题的多个评论 - 有些人说是,有些人说不,而且许多答案都含糊不清.任何人都可以用更简单的术语描述它所在的位置吗?在一篇文章中,我甚至看到有人说它与类内存共享相同的内存位置,类是由类加载器加载的 - 这是真的吗?
假设一个64位JVM,将MaxPermSize保持为小有什么显着的好处吗?
这是在经常重新部署的Java EE应用程序的上下文中,并且具有类加载器泄漏.作为一个中期解决方案,将MaxPermSize提升到一个荒谬的值似乎是非常合理的 - 只要它不会破坏磁盘交换空间.
由于取消部署的应用程序代码几乎全部未使用(除了涉及泄漏的代码),因此操作系统会将其分页.因此,未部署碎屑对物理内存的负担似乎可以忽略不计; 这已通过观察RSS(Unix上的工作集大小)得到验证.
还有其他我应该关注的影响吗?
我们在tomcat 6上运行liferay门户.每个portlet都是一个包含的Web应用程序,因此它包含了portlet本身所需的所有库.我们目前有30多个portlet.结果是我们的tomcat的permgen随着我们部署的每个portlet而增加.
我们现在有两条路可以遵循.将每个portlet通常使用的一些库移动到tomcat共享库.这将包括像spring/hibernate/cxf/....这样的东西来减少我们的permgen大小或更容易增加permgen大小.
第二个选项允许我们将每个portlet保持为自包含的实体.
现在的问题是,增加permgen大小会对性能产生负面影响吗?我们目前的运行速度为512MB.我发现很少甚至没有关于此的信息.但发现一些帖子的人都在谈论以1024MB permgen大小运行而没有问题.
我的应用程序显示"老一代"/"终身代"的大小上升,当达到"老一代"的最大限制时,突然PermGen大小增加.这是我的一代sizings:
-Xmx1200m -Xms1200m -Xmn450m -XX:MaxPermSize=600m -XX:+UseParallelGC
Run Code Online (Sandbox Code Playgroud)
这是在32位Fedora上,所以不能有比这更大的堆.
该应用程序没有进行任何花哨的类加载,虽然它使用Spring IOC和Hibernate,但Spring App-context.xml定义了大约1000个Beans.
这个应用程序以175MB PermGen开始,在几小时内稳定增加到~250MB,一直保持到Tenured Generation达到~780 MB,然后permgen跳到~500MB而Old Gen降到~500MB.
这迫使我每天重启应用程序,并让我真正害怕迫在眉睫的OutOfMemory错误..任何见解都会非常有帮助.
谢谢Gala101
13/May:有人可以说一下当'Old Gen'被垃圾收集时会发生什么吗?
jvm是否将"Old Gen"的藏品放入PermGen?
我的PermGen峰值仅在"Old Gen"收集时出现,而OldGen尺寸的减少与PermGen尺寸的增加密切相关.
PS:我没有进行任何实时部署/取消部署,因为这肯定会占用PermGen.
下面是我的监控页面中的当前spanshot :(承诺的部分刚刚从~250 MB跳到500 MB)
PS Perm Gen
Type Non-heap memory
Usage init = 16777216(16384K) used = 254453736(248489K) committed = 504954880(493120K) max = 629145600(614400K)
Peak Usage init = 16777216(16384K) used = 254453736(248489K) committed = 504954880(493120K) max = 629145600(614400K)
Collection Usage init = 16777216(16384K) used = 252421536(246505K) committed = 504954880(493120K) max = 629145600(614400K)
Run Code Online (Sandbox Code Playgroud) 我的日食与OOO:perm-gen错误一起崩溃.我打开了它eclipse.ini来增加它,但令我惊讶的是我发现了两个XXMaxPermSize出现如下所示..我不知道为什么有两个和哪一个要改变.
-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20120522-1813
-product
org.eclipse.epp.package.java.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
512M
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Dhelp.lucene.tokenizer=standard
-Xms40m
-Xmx512m
Run Code Online (Sandbox Code Playgroud)