JVM内存区域划分

253 阅读4分钟

介绍

根据java虚拟机规范的规定,java虚拟机所管理的内存会包括以下几个运行时数据区域:程序计数器(Program Counter Register)、java栈(VM Stack)、本地方法栈(Native

各区域作用讲解

程序计数器

又被称作为PC寄存器,他是一块比较小的内存,可以看作是当前线程所执行字节码的行号指示器。字节码解释器的工作时候就是通过改变这个计数器的值来选取下一条需要执行字节码指令、分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器。 由于java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何时刻,一个处理器(对于多核处理器来说就是一个内核)只会执行一条线程中指令。因此为了线程切换恢复后可以恢复到正确位置,每一条线程都需要一个独立的处理器,各线程之间互不影响。所以我们称这块区域为线程私有区域。

Java虚拟机栈

java虚拟机栈是线程私有的,他与线程的声明周期同步。虚拟机栈描述的是java方法执行的内存模型,每个方法执行都会创建一个栈帧,栈帧包含局部变量表、操作数栈、动态连接、方法出口等。每一个方法的执行到执行完成,对应着一个栈帧在虚拟机中从入栈到出栈的过程。java虚拟机栈栈顶的栈帧就是当前执行方法的栈帧。PC寄存器会指向该地址。当这个方法调用其他方法的时候久会创建一个新的栈帧,这个新的栈帧会被方法Java虚拟机栈的栈顶,变为当前的活动栈,在当前只有当前活动栈的本地变量才能被使用,当这个栈帧所有指令都完成的时候,这个栈帧被移除,之前的栈帧变为活动栈,前面移除栈帧的返回值变为这个栈帧的一个操作数。

本地方法栈

本地方法栈和java虚拟栈基本相同,只不过是针对本地方法。在开发中如或涉及到JNI可能接触本地方法栈多一些,在有些虚拟机中已经将两个合二为一了(比如hotSpot)。

方法区

方法区与Java堆一样,是各个线程的共享区域,用于存储已经被虚拟机加载的类信息、常量、静态变量等。在HotSpot中用永久代来实现方法区,二其他虚拟机是不存在永久代的。Java7已经将运行时的常量池从永久代移除,在Java堆中开辟了一块区域存放运行时常量池。在java8中,已经彻底没有永久代,将方法区直接放在一个与堆不相连的本地内存区域,这个区域叫做元空间。 元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代 之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:-XX:MetaspaceSize,初始空间大小。-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。Java 虚拟机规范中对方法区规定了OutOfMemoryError异常:如果方法区的内存空间不能满足内存分配请求,那 Java 虚拟机将抛出一个OutOfMemoryError异常。

Java堆是Java虚拟机管理内存中最大的一块,是所有线程共享的内存区域,随虚拟机的启动而创建。该区域唯一目的是存放对象实例,几乎所有对象的实例都在堆里面分配。Java 虚拟机规范规定,Java 堆可以出于物理上不连续的内存空间中,只要逻辑上连续即可,如同磁盘空间一样,既可以实现成固定大小,也可以是扩展的,当前主流虚拟机都是 按照扩展来实现的(通过-Xmx 和-Xms 控制)。Java堆是垃圾收集器管理的主要区域,因此也叫"GC堆",细分一点可以分为新生代和老年代;再细致一点新生代可以分为Eden空间、From Survivor空间、ToSurvivor空间。Java 虚拟机规范中对该区域规定了 OutOfMemoryError 异常:如果堆中没有 内存完成实例分配,并且堆无法再扩展则抛出 OutOfMemoryError异常。(当 Old区被放满的之后,进行 Full GC,Full GC 后,若 Survivor 及 old 区仍然无法存放从Eden复制过来的部分对象,则出现 OOM 错误/或者直接存放大对象、大数组,导致老年代空间不足)(详细讲解:待写)





参考文章: > https://juejin.cn/post/6844903621004361741

www.jianshu.com/p/66e4e64ff…

www.cnblogs.com/ityouknow/p…