jdk8:对内存溢出的思考

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012998254/article/details/82755742

jvm内存溢出

JVM管理的几个内存区域分为:

  1. 方法区:用于存储JAVA类信息、常量、静态变量。这个区域也可以发生垃圾回收,比如当一些类不在被引用时JVM可以卸载这个类,不过这种回收动作很少发生。另外所有线程都共享方法区,因此线程对方法区的访问被设计为线程安全的。
  2. 虚拟机栈:JAVA虚拟机栈是线程私有的,每当启动一个新线程时,JVM都会为它分配一个JAVA虚拟机栈。每当线程调用方法时,JVM都会为虚拟机栈压入一个栈帧,该栈帧用于存储参数、局部变量、中间运算结果、方法出口等。虚拟机栈:JAVA虚拟机栈是线程私有的,每当启动一个新线程时,JVM都会为它分配一个JAVA虚拟机栈。没当线程调用方法时,JVM都会为虚拟机栈压入一个栈帧,该栈帧用于存储参数、局部变量、中间运算结果、方法出口等。
  3. 本地方法栈:和虚拟机栈类似,只是他是专为JAVA中的Native方法服务。当线程进入本地方法后,它已经脱离的JVM的限制,甚至可以直接使用本地处理器中的寄存器。实际上本地方法的调用机制非常依赖于JVM的具体实现。本地方法栈:和虚拟机栈类似,只是他是专为JAVA中的Native方法服务。当线程进入本地方法后,它已经脱离的JVM的限制,甚至可以直接使用本地处理器中的寄存器。实际上本地方法的调用机制非常依赖于JVM的具体实现。
  4. 堆:由JVM启动时创建,由所有线程共享,用于存放对象的实例。一般情况下它是JVM中管理的内存中最大的一块。绝大部分JVM内存问题都发生在这一块。 堆:由JVM启动时创建,由所有线程共享,用于存放对象的实例。一般情况下它是JVM中管理的内存中最大的一块。绝大部分JVM内存问题都发生在这一块。
  5. 程序计数器:同虚拟机栈一样,它也是线程私有,启动线程是创建。程序计数器的中保存的内容总是下一条将被执行的指令的地址。 程序计数器:同虚拟机栈一样,它也是线程私有,启动线程是创建。程序计数器的中保存的内容总是下一条将被执行的指令的地址。
    这几个内存区域,除了程序计数器区域外,其他几个区域都有可能发生内存溢出问题。常见的内存溢出有两种:
    1、方法区溢出:jdk中方法区放在元空间里边,如果溢出了,修改-XX:MaxMetaspaceSize。
    在Spring以及Hibernate,Mybatis中都会使用GeneratedConstructorAccessor、动态代理以及CGLib字节码增强技术的等动态生成类,那么就需要强大的方法区来支撑。
    2、Java虚拟机栈与本地方法栈
    栈的大小控制参数时 -Xss。

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

StrackOverFlowError:Java虚拟机在运行中,调用方法时,都要创建栈帧,当栈的空间不够时就会产生StrackOverFlowError。那么对应的解决方法就只能是调节-Xss参数,或者减少方法的调用,减小栈帧的大小两种方式。

OutOfMemeryError:在栈上出现OOM一般是多线程的情形。首先咋们解析一下栈使用的空间可以有多大,拿32位操作系统来举例, 最大内存2G - Xmx(最大堆容量)- MaxPermSize(最大方法区容量)- 虚拟机本身耗费的内存和程序计数器使用的内存。 剩下的内存就是栈可以使用的空间,当Xss配置的参数一定时,那么在不断的创建线程过程中,遇到不能申请到栈空间的时候就会抛出OOM,那么对应的解决方式就是,调节-Xss参数降低栈大小,或者调节-Xmx的大小扩大留给栈的空间。

3.堆内存的溢出
在JVM可使用的最大堆内存可以在启动的时候通过-Xmx参数指定。堆内存溢出是最为常见的内存溢出问题,发生堆内存溢出时,JVM会报告如下错误:java.lang.OutOfMemoryError : java heap space。
在启动JVM的时候加上以下两个参数: -XX:HeapDumpPath=./dumpfile.hprof -XX:+HeapDumpOnOutOfMemoryError

package com.own.learn.jvm.visualVM;

import java.util.HashMap;
import java.util.Map;
public class OOMTest {

    private static final Map map = new HashMap();

    public static void main(String args[]) {

        int i =1;
        while (true) {
            map.put(String.valueOf(i), new TestMemory());
            i++;
        }
    }
}

class TestMemory {
     int[] array = new int[100000];
}

vm options:-Xmx1024m -Xms1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/wangzhenya
启动visualVM,装入快照

在这里插入图片描述
可以看到在出现 OutOfMemoryError 异常错误时进行了堆转储, 导致 OutOfMemoryError 异常错误的线程: main。点击main方法,可以看到执行什么代码内存溢出了。

"main" prio=5 tid=1 RUNNABLE
	at java.lang.OutOfMemoryError.<init>(OutOfMemoryError.java:48)
	at com.own.learn.jvm.visualVM.TestMemory.<init>(CyclicDependencies.java:20)
	at com.own.learn.jvm.visualVM.CyclicDependencies.main(CyclicDependencies.java:13)
	   Local Variable: java.lang.String[]#12

点击类,可以看到使用比较多的变量。
在这里插入图片描述
在概要中,点击查找最大的对象,可以看到。
在这里插入图片描述
然后点击int[],
在这里插入图片描述
可以看到引用的字段,类型,值以及保留。在点击这一列可以看到,字段的一层层的引用。
在这里插入图片描述
点击到最后,可以看到:
在这里插入图片描述
可以看到具体那个类,那个变量
然后分析代码。

堆外内存溢出

Direct Memory:其是堆外缓存Big Memory的一个实现,它能够在内存中序列化大批量对象,而不影响JVM垃圾回收的性能。可通过-XX:MaxDirectMemorySize调整大小,内存不足时抛出OutOfMemoryError或者OutOfMemoryError:Direct buffer memory。

定位JVM内存溢出问题思路总结
Java堆外内存及导致的溢出错误

猜你喜欢

转载自blog.csdn.net/u012998254/article/details/82755742
今日推荐