内存溢出分类及简单演示

一、演示内存溢出

1.Java代码

User类

public class User {

    private String name;
    private String age;

Controller

    @RequestMapping("/yichu")
    public void  yichu(){
        ArrayList<User> data=new ArrayList<User>();
        while (true){
            data.add(new User());//内存溢出
        }
    }

执行以下参数运行程序:

-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

2.在程序运行期间

jstat查看内存信息

从图中可以看出O区 即年老代的内存使用率已经达到99.99%说明是内存溢出了。

3.怎么分析内存溢出?

​ 首先要得到内存信息。

​ jmap -dump 这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。

​ 使用命令 jmap -dump:format=b,file=test.hprof 6740 导出文件格式为hprof的内存信息文件 ,其中的6740是本程序的pid.

​ ![](C:\Users\Administrator\Desktop\jmap -dump.png)

4.使用MAT工具分析内存溢出

​ 找到之前使用jmap指令导出的 test.hprof文件,使用MAT工具导入生成分析。

内存溢出的几种分类

2.1 栈内存溢出(StackOverflowError):

程序所要求的栈深度过大导致,可以写一个死递归程序触发。

2.2 堆内存溢出(OutOfMemoryError : java heap space) 需要分清是 内存溢出 还是 内存泄漏:

(1)如果是内存溢出,则通过 调大 -Xms,-Xmx参数。

(2)如果是内存泄露,则看对象如何被 GC Root 引用。

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

​ 如果应用程序本身比较大,涉及的类库比较多,但是我们分配给持久带的内存(通过-XX:PermSize和-XX:Ma xPermSize来设置)比较小的时候也可能出现此种问题。

​ 一些第三方框架,比如spring、hibernate都是通过字节码生成技术(比如CGLib)来实现一些增强的功能, 这种情况可能需要更大的方法区来存储动态生成的Class文件。

​ 我们知道Java中字符串常量是放在常量池中的,String.intern()这个方法运行的时候,会检查常量池中是否 存和本字符串相等的对象,如果存在直接返回常量池中对象的引用,不存在的话,先把此字符串加入常量 池,然后再返回字符串的引用。

2.3 持久带内存溢出(OutOfMemoryError: PermGen space) 持久带中包含方法区,方法区包含常量池。 因此持久带溢出有可能是(1) 运行时常量池溢出

(2)方法区中保存的Class对象没有被及时回 收掉或者Class信息占用的内存超过了我们配置。 用String.intern()触发常量池溢出。 Class对象未被释放,Class对象占用信息过多,有过多的Class对象。可以导致持久带内存溢出。

2.4 无法创建本地线程

Caused by: java.lang.OutOfMemoryError:unable to create new native thread 系统内存的总容量不变,堆内存、非堆内存设置过大,会导致能给线程分配的内存不足。

java.lang.OutOfMemoryError: unable to create new native thread 最后我们在来看看java.lang.OutOfMemoryError:unable to create new native thread这种错误。

出现这种情 况的时候,一般是下面两种情况导致的:

​ 程序创建的线程数超过了操作系统的限制。对于Linux系统,我们可以通过 ulimit -u 来查看此限制。

​ 给虚拟机分配的内存过大,导致创建线程的时候需要的native内存太少。

​ 建立每个线程,都需要给这个线程分配栈空间。 我们都知道操作系统对每个进程的内存是有限制的,我们启动jvm,相当于启动了一个进程,假如我们一个进 程占用了4G的内存,那么通过下面的公式计算出来的剩余内存就是建立线程栈的时候可以用的内存。

线程栈总可用内存 = 4G -(-Xmx的值)- (-XX:MaxPermSize的值)- 程序计数器占用的内存 

​ 通过上面的公式我们可以看出,-Xmx 和 MaxPermSize的值越大,那么留给线程栈可用的空间就越小,在-Xss参 数配置的栈容量不变的情况下,可以创建的线程数也就越小。因此如果是因为这种情况导致的unable to create native thread,那么要么我们增大进程所占用的总内存,或者减少-Xmx或者-Xss来达到创建更多线程的目的。

猜你喜欢

转载自blog.csdn.net/wf_feng/article/details/82189215