欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

jvm内存结构

程序员文章站 2022-04-18 16:13:55
...

jdk1.8

JVM 内存共分为虚拟机栈、堆、元数据区、程序计数器、本地方法栈五个部分。

程序计数器:线程私有,它可以看做是当前线程所执行 的字节码的行号指示器。不会发生异常

虚拟机栈:线程私有,用于存储栈帧。每个方法执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等。

        局部变量表:是一组变量值存储空间,用于存放方法参数和方法内定义的局部变量(8种基本类型、对象引用和returnAddress类型)

         操作数栈:是一个后入先出栈(LIFO)。随着方法执行和字节码指令的执行,会从局部 变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者 返回给方法调用者,也就是出栈/入栈操作

        动态链接:Java虚拟机栈中,每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,持有这个引用的目的是为了 支持方法调用过程中的动态链接(将符号引用转换成直接引用)

        方法返回地址:程序正常退出或异常退出,都需要返回到方法被调用的位置,程序才能继续进行

本地方法栈:线程私有,与虚拟机栈所发挥的作用是非常相似的, 其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码) 服务, 而本地方法栈则是为虚拟机使用到的本地(Native) 方法服务

堆:jvm共享,Java堆(Java Heap) 是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java世界里“几乎”所有的对象实例都在这里分配内存,jdk1.8后静态变量和常量池等并入堆中

元空间:存储类的元信息。最大可利用空间是整个系统内存的可用空间。

Java堆溢出

public class HeapOOM {
    static class OOMObject {
    }
    public static void main(String[] args) {
        List<OOMObject> oomObjectList = new ArrayList<>();
        while (true) {
            oomObjectList.add(new OOMObject());
        }
} }

说明:不断向oomObjectList添加对象导致GC Roots 到对象之间有可达路径来避免垃圾收集回收机制清除这些对象。新生代满后,会发生Minor GC,GC完成后空间仍不足,将对象放入老年代,老年代空间不足会发生Full GC,之后如果空间还不足以存放新对象则抛 出 OutOfMemoryError 异常。

原因:

        内存中加载数据过多

        集合对对象引用过多且使用完后未清除

        代码存在死循环产生过多重复对象

        堆分配不合理

虚拟机栈和本地方法栈溢出

如果线程请求栈最大深度超过虚拟机所允许的最大深度,会抛出*Error异常。

如果虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够的内存时,将抛出OutOfMemoryError异常。