解决Java Out Of Memory 问题的思考

3,274

  java.lang.OutOfMemoryError 是 java.lang.VirtualMachineError 的子类,当JVM由于内存不足而无法分配对象,并且垃圾收集器无法提供更多内存时, 会抛出这种异常.

  虚拟机可能构造OutOfMemoryError 这个对象, 就好像堆栈不可写或者suppression被禁了一样.

  OutOfMemoryError的类型:

  有两类的OutOfMemory:

  The java.lang.OutOfMemoryError: Java heap space

  The java.lang.OutOfMemoryError: PermGen space

  虽然这两种情况都是由于JVM耗尽了内存而发生的,但是它们彼此之间是非常不同的,并且它们的解决方案是相互独立的。

  源码分析:

  


  我们可以看到, OutOfMemoryError 有两个构造函数, 一个是无参数的,一个是带一个详细消息的构造函数.

  重现java.lang.OutOfMemoryError: Java heap space

  下面一段代码,可以重现OutOfMemory:

  


  运行这个程序, 会出现如下的问题:

  


  在上面的例子中,我们可以看到一个小程序就可以创建OutOfMemoryError,因为只是小的错误步骤。因为它有无限循环,不断地在同一个变量上添加。

  java.lang.OutOfMemoryError: Java heap space 的解决办法

  比较简单的解决办法是: 调节JVM的参数, 增加最大堆的大小: 设置 -Xmx 和 -Xms 比例按照 1:1 或者1:1.5 例如:

  export JVM_ARGS=”-Xms1024m -Xmx1024m”

  如果调节了大小后,还会出现OutOfMemory, 我们就需要用相应的工具来调研内存泄漏问题, 分析程序的Heap Dump文件.

  常用的工具是:

  Eclipse Memory Analyzer(MAT) 分析Heap Dump

  Profiler like Netbeans or JProbe.

  java.lang.OutOfMemoryError: PermGen space的原因

  产生PermGen space 问题的原因主要有二:

  一. 我们通常知道 JVM采用分代垃圾回收, 分为新生代, 年老代和持久代. PermGen是持久代, 所以持久代是用来存储JVM

  class, method相关的各种String Pool, 各种元数据.

  大多数情况下, 持久代的默认size是大约64MB, 那么,实际中, 这个值是容易达到的.

  那么我们就需要调节这个参数的值:

  我们设置XMX, 并不能解决这个问题, 需要设置 “-XX: PermSize” and “-XX: MaxPermSize”

  例如:

  export JVM_ARGS=”-Xmx1024m -XX:MaxPermSize=256m”

  二. 第二个原因是: ClassLoader 产生的内存泄漏. 一般情况下, 这个错误会发生在 GlassFish, Tomcat

  等web server里面.

  在应用服务器中使用不同的类加载器来加载不同的应用程序,以便在不影响同一服务器上其他应用程序的情况下部署和卸载一个应用程序。但是在卸载过程中,如果容器以某种方式保持对应用程序类加载器加载的任何类的引用,那么如果多次部署和卸载应用程序,该类和所有相关的类将不会被垃圾收集并快速填充permGen空间。

  java.lang.OutOfMemoryError: PermGen space 的解决办法

  正如上面所述, 第一个解决办法是调节参数,

  export JVM_ARGS=”-XX:PermSize=64M -XX:MaxPermSize=256m”

  当然, 如果同样的问题还会出现的话, 就需要具体分析下内存的泄漏情况了.

  常用的工具是:

  Eclipse Memory Analyzer(MAT) 分析Heap Dump

  Profiler like Netbeans or JProbe.

  以上,内存泄露分析和解决,供参考。