本文由 ImportNew - Peter Pan 翻译自 javacodegeeks。如需转载本文,请先参见文章末尾处的转载要求。
html
ImportNew注:若是你也对Java技术翻译分享感兴趣,欢迎加入咱们的 Java开发 小组。参与方式请查看小组简介。 java
垃圾回收是Java开发人员理解得最不完全的地方之一。他们以为既然JVM负责垃圾回收,那么便没必要担忧内存的分配跟回收等问题。可是当应用变得复杂的时候,垃圾回收一样变得复杂起来,并且一旦垃圾回收变得复杂,程序的性能就会受到影响。因此,这篇文章将会帮助Java开发人员更好地理解垃圾回收机制是怎样工做的,以及如何修复Java中的“Out of Memory”问题。有两个十分广泛的致使“Out of Memory”问题的因素。第一个是堆大小,第二个就是PermGen Space。 apache
永久代和类加载器 数组
Java对象是Java类的实例。每一次建立一个新的Java对象,JVM就会建立一个该对象的内部标识并把该对象存储在堆中。若是是首次访问该类,JVM就必须加载它。类加载是定位相关类文件、在硬盘上找到该文件、加载该文件并解析文件结构的一系列过程。确保类的正确加载是类加载器(ClassLoader)的责任。一个Java程序中的每个类都必须被相同的类加载器加载。类加载器是java.lang.ClassLoader类的实例。类加载器把Java类暂时加载到Perm Space中。 tomcat
JVM也建立了Java类的内部标识并把java类存储在永久代中。在垃圾回收期间,对象跟类都被看做对象且用相同的方式进行垃圾回收。最初,类和对象都被存储在堆空间。 服务器
做为优化性能,会建立永久代并将被放在永久代中。类是咱们的JVM实现的一部分,而且咱们不该该用数据结构填满Java堆。永久代内存分配在堆以外,包含如下类的信息: 数据结构
类的方法 框架
类的名字 性能
常量池信息 优化
跟类有关的对象数组和类型数组
JVM使用的内部对象
编译器优化的使用信息
既然如今咱们已经理解了永久代是什么,那么就让咱们看一看是什么引起了内存问题。
PermGen Space
当JVM须要加载一个新类的定义的却发如今PermGen没有足够的空间时,”java.lang.OutOfMemoryError: PermGen Space”错误便发生了。默认分配的永久代内存空间(PermGen Space),服务器模式是64M,客户端模式是32M。有两个可能缘由致使永久代内存空间问题。
第一个缘由多是你的应用程序或服务器拥有太多的类,而已有永久代内存空间不足以容纳全部的类。
-XX:MaxPermSize=XXXM
若是出现OOM,这是由于类太多而引发的永久代内存空间不足,那么你能够经过增长 +XX:MaxPermGenSize=XXXM 大小的方式来增长永久代的内存空间。这样作会加大存储类的空间变量的大小,而且 +XX:MaxPermGenSize 参数应该设置为256M。
-XX:+CMSClassUnloadingEnabled
这个参数显示在使用CMS GC时,未加载类是否可用。该参数默认值为false,由此,你须要在java选项中显示设置下面选项:
1
|
-XX:+CMSClassUnloadingEnabled
|
若是你启用 CMSClassUnloadingEnabled ,JVM进行GC时便会清除永久代,而且删除再也不使用的类。这个选项只会在 UseConcMarkSweepGC 可用时才起做用。经过如下选项使 UseConcMarkSweepGC 可用:
1
|
-XX:+ UseConcMarkSweepGC
|
-XX:+CMSPermGenSweepingEnabled
这个参数显示清除永久代是否可用。默认状况下这个参数是不可用的,因此要协调永久代问题,就必须显示设置这个参数。这个参数在Java 6里面被删除,因此若是你在使用Java 6或以上版本,你将不得不使用 -XX:+CMSClassUnloadingEnabled 选项。因此,为了解决永久代空间的内存问题,被添加的选项看起来以下:
1
|
-XX:MaxPermSize=128M –XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled
|
内存泄漏
第二个缘由多是内存泄露。被加载的类定义如何变成没有被使用?
正常状况下,在Java中类是永久存在的。因此一旦类被加载,他们将一直停留在内存中,即使其所在应用服务器端已经中止运行。像cglib这样的动态类产生库,在他们动态建立了大量类以后,会使用大量永久代内存空间。在运行时建立的代理类被普遍地使用。当单个类定义被用于产生多个实例时,建立新的代理类将会很容易。
Spring和Hibernate常常产生某个类的代理,这些代理类被类加载器加载。产生的类定义从不被清理,致使永久性堆空间迅速填满。
为了解决永久代内存空间问题,你须要识别出泄露的缘由并修补它。增大永久代内容空间不会有益于解决却只会延缓这类问题,由于在某种意义上,永久代内存空间终将被填满。
若是你正在使用Tomcat且常常遇到内存溢出问题,最新版本的Tomcat已经有足够的容量来解决某些内存溢出问题。
总结
一旦你遇到永久代内存空间问题,你须要找出这个问题是不是因为你的应用程序加载了大量的类或出现了内存泄露。若是是因为类太多,精确地协调分配永久代内存空间可以解决。若是是因为内存泄露,你须要找到泄露的根本缘由并标记出来。像cglib、Spring、Hibernate这样的框架会动态生成大量的类,因此在使用这些框架时分配更多的永久代内存空间是更好的选择。
原文连接: javacodegeeks 翻译: ImportNew.com - Peter Pan
译文连接: http://www.importnew.com/8133.html