JAVA内存溢出

Posted freelymen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA内存溢出相关的知识,希望对你有一定的参考价值。

  JAVA的内存分为方法区、虚拟机栈、本地方法栈、堆、程序计数器五个部分,除程序计数器外,其它部分都可能出现内存溢出OOM(OutOfMemeryError)。

1、内存溢出和内存泄漏的区别
内存溢出 (Out Of Memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现Out Of Memory。
内存泄露 (Memory Leak):是指程序在申请内存后,由于某种原因无法释放已申请的内存空间,导致这块内存无法再次被利用,造成系统内存的浪费。一次内存泄露危害可以忽略,但内存泄露堆积的后果很严重,无论多少内存,迟早会被占光。
2、内存溢出详解

2.1.Java虚拟机栈与本地方法栈

每个线程栈的大小控制参数时 -Xss。

Java虚拟机在栈中定义了两种异常,StrackOverFlowError和OutOfMemoryError:unable to create new native thread。当请求栈的深度大于java虚拟机所允许的最大深度则抛出StrackOverFlowError;如果Java虚拟机在栈扩展时,没有申请到足够的空间时,则抛出OutOfMemoryError:unable to create new native thread。

StrackOverFlowError:单线程内占用内存超过了栈的大小-Xss

出现场景

一、局部数组或集合过大。一般出现在大查询或大导出的情况下。

二、方法调用太多。一般出现在递归调用层次太多或死循环时。

三、指针或数组越界。这种情况最常见,例如进行字符串拷贝,或处理用户输入等等。

解决方式

优化程序、减少方式的调用、增大-Xss参数

OutOfMemoryError:unable to create new native thread:多线程占用的内存超过了可用内存(进程可用内存(32位操作系统时为2G)-Xmx-MaxPermSize-虚拟机本身耗费的内存和程序计数器使用的内存)

解决方式

减少线程数量、降低-Xss的大小(即减少每个线程拥有的内存大小)、降低-Xmx以及MaxPermSize的大小扩大留给栈的空间

2.方法区内存溢出

方法区的大小通过-PermSize和-MaxPermSize控制。

当持久带溢出的时候抛出 java.lang.OutOfMemoryError: PermGen space

因为类常量和运行时常量也存储在方法区中,所以运行时常量过多也可导致方法区的OOM,但是没有直接控制常量池大小的参数,只能通过-PermSize和-MaxPermSize来间接控制。

出现场景

一、在Spring以及Hibernate,Mybatis中都会使用GeneratedConstructorAccessor、动态代理以及CGLib字节码增强技术的等动态生成类,那么就需要强大的方法区来支撑。

二、运行时常量池溢出

三、使用一些应用服务器的热部署的时候,我们就会遇到热部署几次以后发现内存溢出了,这种情况就是因为每次热部署的后,原来的Class没有被卸载掉。

解决方式

一、增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中XX:PermSize是初始永久保存区域大小,XX:MaxPermSize是最大永久保存区域大小。如针对tomcat6.0,在catalina.sh 或catalina.bat文件中一系列环境变量名说明结束处(大约在70行左右) 增加一行:
JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m"
如果是windows服务器还可以在系统环境变量中设置。感觉用tomcat发布sprint+struts+hibernate架构的程序时很容易发生这种内存溢出错误。使用上述方法,我成功解决了部署ssh项目的tomcat服务器经常宕机的问题。
二、清理应用程序中web-inf/lib下的jar,如果tomcat部署了多个应用,很多应用都使用了相同的jar,可以将共同的jar移到tomcat共同的lib下,减少类的重复加载。这种方法是网上部分人推荐的,我没试过,但感觉减少不了太大的空间,最靠谱的还是第一种方法。

3.堆内存溢出

堆的大小通过-Xms和-Xmx设置

堆内存溢出的时候,虚拟机会抛出 java.lang.OutOfMemoryError:java heap space

出现场景

创建对象时如果没有可以分配的堆内存,JVM就会抛出OutOfMemoryError:java heap space异常

解决方式

首先需要分清是内存溢出还是内存泄露

(1)如果是内存溢出,则通过 调大 -Xms,-Xmx参数。
(2)如果是内存泄露,则看对象如何被 GC Root 引用。

出现此种情况的时候,我们需要根据内存溢出的时候产生的 dump 文件来具体分析(需要增加 -XX:+HeapDump
OnOutOfMemoryError jvm启动参数)。出现此种问题的时候有可能是内存泄漏,也有可能是内存溢出了。

1、配置方法

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${目录}。
2、参数说明

(1)-XX:+HeapDumpOnOutOfMemoryError参数表示当JVM发生OOM时,自动生成DUMP文件。

(2)-XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径,也可以指定文件名称,例如:-XX:HeapDu
mpPath=${目录}/java_heapdump.hprof。如果不指定文件名,默认为:java_<pid><date><time>_heapDu
mp.hprof。
如果是内存泄漏,我们要找出内存泄漏的对象是怎么被GC ROOT引用起来,然后通过引用链来具体分析泄露的
原因。

如果出现了内存溢出问题,这往往是程序本生需要的内存大于了我们给虚拟机配置的内存,这种情况下,我
们可以采用调大-Xmx来解决这种问题。

 




























以上是关于JAVA内存溢出的主要内容,如果未能解决你的问题,请参考以下文章

java内存溢出的问题如何排查

Java内存溢出异常(上)

java程序内存溢出一般啥原因

java内存溢出怎么解决?

java栈内存溢出怎么解决

内存溢出