JVM内存模型(JAVA)

提示:本文内容来自于官方文档与日常积累,无法保证完全准确;若读者发现错误,欢迎留言指出。

前言

当面试官问JVM的内存模型时,我们常常回答:JVM内存模型包括五个部分,即程序计数器、堆、虚拟机栈、本地方法栈、方法区。注意,这个结构来自于官方文档(文档里面还提到了运行时常量池,由于其属于方法区的一部分,因此未被单独罗列),并且,这只是规范,是参考,我们实际使用的JVM虚拟机的划分标准与规范很像,但非一模一样,后续将以HotSpot虚拟机为例。其中程序计数器、栈是线程私有的,每个线程都拥有独立的程序计数器和栈;而堆和方法区是线程共享的。

下述中的英文全部节选自官方文档

JVM内存模型规范

程序计数器(The pc Register)

JVM是多线程执行的,为了线程切换后能够恢复到正确的执行位置,每条线程需要有一个独立的程序计数器。对于一个非native线程,程序计数器指向正在执行的指令的地址;对于native线程,程序计数器未定义。程序计数器也是唯一没有OutOfMemoryError异常的区域,因为它不受外部程序的控制。

The Java Virtual Machine can support many threads of execution at once (JLS §17). Each Java Virtual Machine thread has its own pc (program counter) register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method for that thread. If that method is not native, the pc register contains the address of the Java Virtual Machine instruction currently being executed. If the method currently being executed by the thread is native, the value of the Java Virtual Machine’s pc register is undefined. The Java Virtual Machine’s pc register is wide enough to hold a returnAddress or a native pointer on the specific platform.

虚拟机栈(Java Virtual Machine Stacks)

每个线程在创建时都会被分配一个虚拟机栈,使用参数-Xss调整线程栈大小。更多的JVM调优参数可参考官方文档

Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
In the First Edition of The Java® Virtual Machine Specification, the Java Virtual Machine stack was known as the Java stack.

栈的生命周期与线程相同,用于支持程序方法调用与方法执行的数据结构,当需要执行某个方法时,需要在栈中创建一个栈帧。栈帧又主要分为操作数栈,动态链接,局部变量表,方法出口等部分。

  • 局部变量:每个函数的局部变量,参数列表。
  • 操作数栈:执行指令的时候,需要将指令加入到操作数栈当中,而此时执行的每一条指令都需要压入到操作数栈里面。
  • 动态链接:每个栈帧包含一个指向运行时常量池(运行时常量池的定义在下面)的引用,动态链接就是通过这个引用将方法的符号变量转换为方法的具体实现,并加载类文件来解释当前未定义的符号。
  • 方法出口:包含正常方法返回出口(没有exception)和异常方法返回出口。

如果一个线程在计算时所需要用到栈大小超过配置允许最大的栈大小,那么Java虚拟机将抛出 StackOverflowError异常(递归调用不合理很容易造成该异常);如果进行动态扩展时如果无法申请到足够内存,会抛出 OutOfMemoryError 异常。

本地方法栈

与虚拟机栈作用相似,也会抛出StackOverflowError和OutOfMemoryError异常。区别在于虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈是为虚拟机使用到的Native方法(使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用)服务。

*具体的虚拟机实现中内存结构是有差异的,如在Hotspot虚拟机中,虚拟机栈和本地方法栈融为一体。

An implementation of the Java Virtual Machine may use conventional stacks, colloquially called “C stacks,” to support native methods (methods written in a language other than the Java programming language). Native method stacks may also be used by the implementation of an interpreter for the Java Virtual Machine’s instruction set in a language such as C. Java Virtual Machine implementations that cannot load native methods and that do not themselves rely on conventional stacks need not supply native method stacks. If supplied, native method stacks are typically allocated per thread when each thread is created.

堆被所有线程共享,主要存放运行时的对象实例以及数组,并且由垃圾收集器管理内存。-Xms表示堆初始化堆大小,-Xmx表示最大堆大小。

The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.
The heap is created on virtual machine start-up. Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector); objects are never explicitly deallocated. The Java Virtual Machine assumes no particular type of automatic storage management system, and the storage management technique may be chosen according to the implementor’s system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous.

方法区

用于存储类结构如运行时常量池、方法数据、域,以及方法和构造器代码。注意JVM标准中提到(如下),方法区逻辑上属于堆,但可能并不需要垃圾回收器,并且没有强制要求放在哪片区域。
*在jdk1.7之前,Hotspot中的方法区与堆在逻辑上还是分开的,但在物理上是一块连续的区域,此时的方法区也被叫做永久代,与新生代、老年代一起进行垃圾回收;在jdk1.7中,主体没变,但是永久代中的字符串常量池移到了堆中;而到了jdk1.8,Hotspot移除永久代的概念,改为元空间,此时方法区由 元空间+堆 的形式实现。移除永久代出于两点考虑:1、永久代容易出现OOM问题,不好维护,并且执行回收的影响整体效率;2、与JRockit合并,其中没有永久代的概念。

The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the “text” segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods used in class and interface initialization and in instance initialization (§2.9).
The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.

常量池(或称静态常量池)与运行时常量池

常量池(也叫静态常量池)指的是编译之后的.class文件中存储字面量和符号引用的部分。在Class文件结构中,最头的4个字节用于 存储魔数 (Magic Number),用于确定一个文件是否能被JVM接受,再接着4个字节用于 存储版本号,前2个字节存储次版本号,后2个存储主版本号,再接着是用于存放常量的常量池,包括常量字面量(即final修饰的变量的赋值)和符号引用。常量池可以理解为一个符号表,一个哈希表,用于快速查找每个符号如方法名,字段名所对应的具体的内容。

运行时常量池在规范中被定义为方法区的一部分,是每个类的运行时状态,其中的一部分就是将class文件常量池中的内容转存到运行时常量池中,将符号引用改为地址引用。其中专门用于存储字符串的部分称为字符串常量池,以哈希表形式实现。在jdk1.7中从运行时常量池中分离放到了堆中。到了jdk1.8,原来放在永久代的部分被移到元空间中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值