很多开发运维人员都有遇到过java.lang.OutOfMemoryError这个错误,原因无外乎两点:JVM内存过小、程序不严密产生了过多的垃圾。具体来说有以下几种:
- JVM启动参数内存值设定的过小。
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据。
- 集合类中有对象引用,使用完后未清空,使得JVM不能回收;
- 代码中存在死循环或循环产生过多重复的对象实体;
- 使用的第三方软件中的有BUG;
此类错误在Tomcat中常见的错误提示有两种:
java.lang.OutOfMemoryError: PermGen space java.lang.OutOfMemoryError: Java heap space
第一条中的PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,也称”永久代”,用于存储虚拟机(JVM)加载的类(class)信息、常量、静态变量、是各个线程共享的内存区域。类在被载入(Loader)时就被放到该区中。GC(Garbage Collection垃圾回收机制)不会在主程序运行期对该区进行清理。所以如果程序中有很多类的话,就很可能出现java.lang.OutOfMemoryError: PermGen space错误, 这种错误常见在web服务器对JSP进行预编译(pre compile)的时候。如果WEB APP下都用了大量的第三方jar,其大小超过了jvm设置默认的大小(不同JVM默认值不尽相同,网上常说的默认最小值为16MB,最大值为64MB),那么就会产生此错误信息了。 简单粗暴的解决方法是在TOMCAT_HOME/bin/catalina.sh中通过手动指定-XX:PermSize、-XX:MaxPermSize参数限制该区的大小。
第二条中的Heap space是指堆区,是指java程序运行过程中JVM可以调配使用的内存空间,Heap的大小是年轻代(Young Generation)和老年代(Tenured Generaion)之和。默认其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。
最后说下TOMCAT_HOME/bin/catalina.sh设置JAVA_OPTS格式和说明:
#常用格式: JAVA_OPTS="-server -Xms512m -Xmx1024m -Xss2048K -XX:PermSize=512m -XX:MaxPermSize=1024m" #参数说明: -server:一定要作为第一个参数,在多个CPU时性能佳 -Xms:初始Heap大小,使用的最小内存,cpu性能高时此值应设的大一些 -Xmx:指定heap最大值,使用的最大内存 -XX:PermSize: 设定内存的永久保存区域 -XX:MaxPermSize:设定最大内存的永久保存区域 +XX:AggressiveHeap 会使得 Xms没有意义。这个参数让jvm忽略Xmx参数,疯狂地吃完一个G物理内存,再吃尽一个G的swap。 -Xss:每个线程的Stack大小 -verbose:gc 现实垃圾收集信息 -Xloggc:gc.log 指定垃圾收集日志文件 -Xmn:young generation的heap大小,一般设置为Xmx的3-4分之一 -XX:+UseParNewGC :缩短minor收集的时间 -XX:+UseConcMarkSweepGC :缩短major收集的时间。提示:此选项在Heap Size 比较大而且Major收集时间较长的情况下使用更合适。