Java开发人员最不了解的领域之一是垃圾收集。 Java开发人员认为JVM负责垃圾收集,因此他们不必担心内存分配,释放等问题。但是,随着应用程序变得越来越复杂,垃圾收集也会变得越来越复杂,一旦性能变得复杂,性能便会受到影响。 因此,这将有利于Java开发人员了解垃圾回收的工作原理以及如何解决Java中的“内存不足”问题。 有2个非常常见的“内存不足”问题。 第一个是“堆大小”,第二个是“ PermGen空间”。
永久生成器和ClassLoader。
Java对象是Java类的实例。 每次创建新的Java对象时,JVM都会创建该对象的内部表示并将其存储在堆中。 如果是第一次访问该类,则必须由JVM加载它。 类加载是以下过程:查找相应的类文件,在磁盘上查找文件,加载文件并解析结构。 确保正确加载类是ClassLoaders的责任。java程序中的每个类都需要由同一ClassLoader加载。 ClassLoader是java.lang.ClassLoader类的实例。 现在,ClassLoader将Java类加载到Perm Space中。
JVM还创建了Java类的内部表示,这些类存储在永久代中。 在垃圾回收期间,java对象和类都被视为对象,并且以相同的方式进行垃圾回收。 最初,java对象和类都存储在堆空间中。
为了优化性能,创建了永久代,并在其中放置了类。类是我们JVM实现的一部分,我们不应该用数据结构填充Java堆。 永久代分配在堆大小之外。 永久世代包含以下类信息:
- 一类的方法。
- 类的名称。
- 常量池信息。
- 与类关联的对象数组和类型数组。
- JVM使用的内部对象。
- 编译器用于优化的信息。
现在我们了解了什么是永久生成,让我们看看是什么导致该区域的内存问题。
PermGen空间
当JVM需要加载新类的定义并且PermGen中没有足够的空间时,会发生“ Java.Lang.OutOfMemoryError:PermGen空间”。 服务器模式分配的默认PermGen空间为64 MB,客户端模式分配的默认为32 MB。 发生PermGen Space问题的原因可能有两个。
第一个原因可能是您的应用程序或服务器中的类太多,而现有的PermGen Space无法容纳所有类。
-XX:MaxPermSize = XXXM
如果问题是由于类数量过多而导致PermGen空间不足,则可以通过添加–XX:MaxPermSize = XXm参数来增加PermGen空间。 这将增加可用于存储类的空间,并且应-XX:MaxPermSize = 256m
-XX:+ CMSClassUnloadingEnabled
此参数指示使用CMS GC时是否启用类卸载。 默认情况下,此选项设置为false,因此要启用此功能,您需要在java options中显式设置以下选项。
-XX:+ CMSClassUnloadingEnabled
如果启用CMSClassUnloadingEnabled,则GC也会清除PermGen,并删除不再使用的类。仅当使用以下选项启用UseConcMarkSweepGC时,此选项才有效。
-XX:+ UseConcMarkSweepGC
-XX:+ CMSPermGenSweepingEnabled
此参数指示是否启用了扫描电烫。 默认情况下,此参数是禁用的,因此需要显式设置此参数以微调PermGen问题。 在Java 6中已删除此选项,因此,如果使用Java 6或更高版本,则需要使用-XX:+ CMSClassUnloadingEnabled。 因此,为解决PermGen Space内存问题而添加的选项如下所示
-XX:MaxPermSize = 128m -XX:+ UseConcMarkSweepGC XX:+ CMSClassUnloadingEnabled
内存泄漏
第二个原因可能是内存泄漏。 装入的类定义可能如何变得未使用。
通常在Java中,类是永远的。 因此,一旦加载了类,即使该应用程序在服务器上停止,它们也会保留在内存中。 像cglib这样的动态类生成库使用了许多PermGen Space,因为它们动态创建了很多类。 大量使用Proxy类,这些类是在运行时综合创建的。 当单个类定义可用于多个实例时,创建新的代理类很容易。
Spring和Hibernate通常代理某些类。 此类代理类由类加载器加载。 永远不会丢弃生成的类定义,从而导致永久堆空间快速填充。
对于PermGen空间问题,您将需要确定泄漏原因并加以解决。 增加PermGen空间将无济于事,只会延迟问题,因为在某些时候PermGen空间仍会被填满。
如果您使用的是Tomcat并因内存泄漏而困扰,那么最新版本的Tomcat可以修复某些内存泄漏问题。
- http://wiki.apache.org/tomcat/MemoryLeakProtection
结论
一旦遇到PermGen Space问题,您将需要找出问题是由于您的应用程序正在加载大量类还是由于内存泄漏引起的。 如果是由于类数量过多,您可以进行微调以增加分配的PermGen空间,这将解决此问题。 如果问题是由于内存泄漏引起的,则需要找到泄漏的根本原因并加以解决。 某些框架的工作方式如cglib,Spring,Hibernate会创建大量动态生成的类,因此最好使用这些框架为项目分配更多的PermGen Space。
翻译自: https://www.javacodegeeks.com/2013/12/decoding-java-lang-outofmemoryerror-permgen-space.html