打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
java.lang.OutOfMemoryError的两种解决办法

         不管是现在还是将来,每个java开发人员都会遇到java.lang.OutOfMemoryError错误。尽管开发人员也会因为造成内存的泄漏而出现OutOfMemoryError错误,但这个问题更多是由于系统的限制引起的,而不是开发人员的错。我发现关于引起这个错误的原因和解决办法尽管很平常很基础,但在很多年轻的开发者仍然对他们一无所知。这篇文章我们将探索什么是java.lang.OutOfMemoryError错误,为什么这个错误会出现在我们的程序中,不同OutOfMemoryError错误的区别以及如何修正这个错误。这篇文章只是纯粹的提供关于java.lang.OutOfMemoryError基础知识,而不会对它进行详细讨论。

      什么是java.lang.OutOfMemoryError?

       Java.lang.OutOfMemoryError是java.lang.VirtualMachineError的子类。在堆耗尽内存的时候,jvm会抛出Java.lang.OutOfMemoryError。这个错误大多数出现在当你去创建一个对象,但是在堆中却不能为这个对象分配足够多空间的时候。而且在java api文档中,并没有对这个错误做大量的解释。

     OutOfMemoryError的类型

      在java中有两种主要的OutOfMemoryError类型:                                                                            
(1) Java.lang.OutOfMemoryError: Java heap space
(2) Java.lang.OutOfMemoryError: PermGen space
尽管它们都发生在内存耗尽的情况下,但它们之间是相当不同的,它们的解决办法也是各不一样。

        两种OutOfMemoryError之间的区别

           如果你熟悉堆的历代版本和垃圾收集器的工作原理,并且知道到新的,老的和永久的堆空间,那么你将会非常容易解决OutOfMemoryError错误。永久的堆空间用于存储jvm相关类,方法和其他实体的字符串池和各种元数据。因为大多数jvm默认的Perm Space(永久的堆空间)的大小是64M左右,所以如果你的工程里有太多的类或者数量巨大的字符串的话,那么很容易就会耗尽内存。需要指出的一点是它并不依赖” Xmx”(译者注: -Xms  指JVM初始分配的堆内存,-Xmx  指 JVM最大允许分配的堆内存)的值,所以不管你的堆空间多么大,一样会耗尽Perm Space。好的办法是你可以根据工程的需要通过JVM的选项指定永久堆空间的大小,即'-XX:PermSize' and  '-XX:MaxPermSize'。
一个很小的事情是要记得在指定堆的Perm Space(永久的堆空间)的大小的时候需要用”=”来分离参数名称和值,但在指定堆得最大值的时候是不需要“=”的,正如下面的例子一样:
Export  JVM_ARGS='-Xmx1024m -XX:MaxPermSize=256m'
           'java.lang.OutOfMemoryError: PermGen'的另一个原因是类加载器造成的内存泄漏,它经常出现在web服务器和应用服务器中,例如tomcat, webshere, glassfish or weblogic。在应用服务器中,不同的类加载器用于加载不同的web应用,以便在相同的服务器上部署和取消部署一个应用而且不会影响其他的应用程序。但是当取消部署的时候,如果容器持有类加载器已经加载的类的引用,那么这个类和相关的类就不会被垃圾回收器回收。如果你部署和取消部署你的应用很多次,那么很快PermGen space就会被填满。'java.lang.OutOfMemoryError: PermGen”在我们的上一个项目中的tomcat里已经被发现多次,但是这个问题的解决办法实在是令人捉摸不透。因为你首先知道哪个类引起了内存泄露,然后你才能修正它。这个问题的另一个原因是应用启动了一些线程,但是当取消部署的时候,这些线程并没有退出。
              这只是一些臭名昭著的类加载器造成内存泄露的例子,任何人在编写加载类和取消加载类的代码的时候都要非常小心以避免这些问题。你也可以使用visualgc 监测PermGen space,这个工具会展示PermGen space的使用情况图表,你可以看到PermGen space是怎样并且何时增长的。我建议在得出任何结论之前先使用这个工具。
关于'java.lang.OutOfMemoryError: PermGen'的原因,我们发现另一个更加无知但有趣的是对于 JVM 的参数 '-Xnoclassgc'的介绍。这个选项用于避免加载和取消加载一些已经没有被引用的类,这样可以避免因为频繁的加载和取消加载而影响性能。但是在J2EE环境中使用这个选项是很危险的,因为许多框架,例如struts,spring等使用反射机制去创建类,并且会频繁的部署和取消部署,如果上一个引用没有被清除,那么很快PermGen space就会被耗尽。这个例子也说明一些时候错误的JVM参数或配置也会引起OutOfMemoryError错误。
            所以结论是不要在J2EE环境中使用'-Xnoclassgc',尤其是在应用服务器上。

         Tomcat解决Java.lang.OutOfMemoryError: PermGen space错误的办法

         对于tomcat6.0及其以上版本,提供了内存泄漏侦测的能力。它可以通过web应用视图展示一些侦测到的平常的内存泄漏问题,例如web应用中的ThreadLocal内存泄漏,JDBC驱动注册,RMI ,LogFactory和线程等。你可以在htp://wiki.apache.org/tomcat/MemoryLeakProtection 查看具体的细节,也可以通过tomcat提供的管理程序侦测内存泄漏。你如果想在web应用程序上检验内存泄漏问题,使用tomcat是个不错的主意。

          如何解决java.lang.OutOfMemoryError: Java heap space

         1) 解决OutOfMemoryError的简单方法是通过指定JVM参数'-Xmx512M'来指定最大的堆空间,这种方法效果立竿见影。当我使用eclipse,maven,ant编译工程遇到OutOfMemoryError的时候,我更喜欢使用这种办法。这里有一个增加JVM堆空间的例子,建议为你的程序增加堆空间的时候最好保持-Xmx 相比-Xms 是1:1或者1:1.5的比例。
例: export JVM_ARGS='-Xms1024m -Xmx1024m'
           2) 第二种解决办法是很困难的,当你拥有的内存并不多或者在你增加了堆内存但是你依然会遇到OutOfMemoryError错误时,这种情况下你可能想要去分析你的应用程序并且寻找内存泄漏的原因。你可以使用Eclipse Memory Analyzer来检查heap dump,或者可以使用Netbeans, Jprobe等这些分析工具。这种方法比较困难,需要花费大量时间去分析找出内存泄漏的原因。

           如何解决java.lang.OutOfMemoryError: PermGen space

           正如前面讲到的一样,java.lang.OutOfMemoryError: PermGen space发生在永久堆内存耗尽的情况下。要修正这个情况,需要通过JVM选项   '-XX:MaxPermSize'来增加Perm space的最大大小,也可以通过'-XX:PermSize'指定Perm space的初始大小。同时设置这两个值,可以避免在Perm Space重置大小的时候发生完全的垃圾回收。下面是设置初始化和最大值的例子:
export JVM_ARGS='-XX:PermSize=64M -XX:MaxPermSize=256m'
           有时候java.lang.OutOfMemoryError是莫名其妙的,这种情况下分析是最终的解决办法。尽管你有增加堆内存的空间的自由,但还是建议遵循内存管理实践,在编码的时候将没用的引用设置为null。以上我对OutOfMemoryError的全部理解,我也在其他的一些帖子中努力写出java关于查找内存泄漏的文章和使用分析器的方法。希望你也能分享解决OutOfMemoryError的观点。
           注意: 对于tomcat6.0及其以上版本,提供了内存泄漏侦测的能力。它可以通过web应用视图展示一些侦测到的平常的内存泄漏问题,例如web应用中的ThreadLocal内存泄漏,JDBC驱动注册,RMI ,LogFactory和线程等。你可以在htp://wiki.apache.org/tomcat/MemoryLeakProtection 查看具体的细节,也可以通过tomcat提供的管理程序侦测内存泄漏。你如果想在web应用程序上检验内存泄漏问题并且找到PermGen space造成的OutOfMemoryError的原因,使用tomcat是个不错的主意。

          调查修正OutOfMemoryError的工具

             Java.lang.OutOfMemoryError是一种你需要做大量的调查才能找到根本原因的错误。没有对内存工具的足够了解,你不可能做某些事情,例如查找哪个对象在占用内存,占用了多少内存,以及找到可怕的内存泄漏等等。这里我列出一些免费的工具可以帮助你分析堆的使用情况,以及造成OutOfMemoryError的罪魁祸首。

             1)Visualgc

              Visualgc代表Visual Garbage Collection Monitoring Tool 。你可以将它用于你的hostspot JVM。Visualgc最大的优势是能生动展现出各种关键数据,包括类加载器,垃圾回收和JVM编译器性能数据。
JVM被识别是通过虚拟机的标识符,称为: vmid。你可以在这了解更多关于visualgc和vmid的东西。

              2)Jmap

             Jmap是来自JDK6的命令行工具,它允许你将堆的内存转储信息保存到文件中。而且很方便使用,如:jmap -dump:format=b,file=heapdump 6054
这里指定的内存转储的文件名称是heapdump,6054是java进程的PID。你可以通过'ps -ef”或者windows任务管理器或者“jps”工具(Java Virtual Machine Process Status Tool)查找PID.

              3) Jhat

             Jhat之前被称为hat (heap analyzer tool),现在它是JDK6的一部分,你可
以使用Jhat去分析'jmap'生成的文件。Jhat也是一个命令行工具,你可以在windows命令行这样使用它,如: jhat -J-Xmx256m heapdump 
这里它会分析“heapdump”文件中的内存问题。当你启动Jhat后,它就会读取内存转储文件,并且在http端口监听。只需要通过浏览器进入端口,你就可以开始分析内存转储文件中的对象。Jhat默认监听7000端口。

              4)Eclipse memory analyzer

              Eclipse memory analyzer (MAT)是来自eclipse基金会的一个分析java堆内存的工具。它能帮助你找到类加载器的泄漏,内存泄漏和减少内存消耗。你可以使用MAT分析内存转储中数以百万计的对象,也可以帮助你提取怀疑的内存泄漏。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
关于:java.lang.OutOfMemoryError
java.lang.OutOfMemory及其解决方法
java.lang.OutOfMemoryError: PermGen space及其解决...
内存泄露java.lang.OutOfMemoryError: PermGen space解决方法
java.lang.OutOfMemoryError异常解决方法
Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服