Java内存区域与内存溢出异常

2020-02-04  本文已影响0人  官子寒

1. 运行时数据区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的区域

Java虚拟机运行时数据区

1.1 程序计数器

1.2 Java虚拟机栈

1.3 本地方法栈

1.4 Java堆

1.5 方法区

1.6 运行时常量池

1.7 直接内存

2. 对象访问

Object object = new Object();

对象访问方式

  1. 句柄池:reference存储句柄池地址,句柄池存储对象的实例数据和类型数据各自的具体地址信息
    优点:稳定,对象被一定(垃圾回收)只改变句柄中实例数据的指针,reference本身不会改变
  2. 直接指针:reference直接存储地址
    优点:速度快

3. OutOfMemory异常

3.1 Java堆溢出

Intellij IDEA 设置启动JVM参数

-server
-Xms128m
-Xmx512m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Dawt.useSystemAAFontSettings=lcd
-Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine
-Dsun.tools.attach.tmp.only=true

解决手段

  1. 通过内存映像分析工具对dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要分析是出现了内存泄露还是内存溢出
  2. 如果是内存泄露,则用工具查看GCRoots的引用链,准确定位泄露代码的位置
  3. 如果是内存溢出,则检查是否存在某些对象是否生命周期过长、持有持续时间过长等情况

3.2 虚拟机栈和本地方法栈

public class demo {
    int stackDepth = 1;

    public void seekDepth() {
        stackDepth ++;
        this.seekDepth();
    }
    public static void main(String[] args) {
        demo de = new demo();

        try {
            de.seekDepth();
        } catch (Throwable e) {
            System.out.println("-------------------" +de.stackDepth);
            e.printStackTrace();
        }

    }
}

原因:系统给每个进程的内存是有限制的,Java用虚拟机参数规定Java堆和方法区的内存最大值,剩余内存为操作系统限制 - Xmx - MaxPermSize,程序计数器消耗内存很小,可以忽略,剩下的内存由虚拟机栈和本地栈瓜分,每个线程分配的内存越多,能分配的线程就会越少,建立线程时就容易把内存耗尽

3.3 运行时常量池溢出

3.4 方法区溢出

3.5 本机直接内存溢出

Java的Unsafe类

上一篇 下一篇

猜你喜欢

热点阅读