¶jvm内存模型
¶java内存结构
¶内存结构图
以下是两个java内存结构图
¶内存结构详解
¶方法区
- 方法区是被java虚拟机线程共享,它被用来存储每个加载进入的类的结构,包括运行时常量池,字段,方法数据,方法代码和构造器。
- 方法区是在虚拟机启动就创建,虽然方法区逻辑上是属于堆的一部分,但是它不被垃圾回收器回收或者是压缩。
- 方法区可以是大小固定,也可以根据需要进行扩展或者收缩。
- 如果java虚拟机不能为方法区分配足够的内存,会出现OutOfMemoryError内存溢出异常。
- 方法区中的运行时常量池。一个运行时常量池是一个class文件被装载后,class中的常量池被载入内存,并保存到方法区。每个运行时常量池在java虚拟机的方法区被分配,当一个类或者接口被创建时,相应的运行时常量池也会被创建。
¶java堆
- java堆是被所有java虚拟机线程共享的。堆在运行时内存区,类实例对象和数组将会在这里被分配内存。
- 堆在虚拟机启动时就被创建。堆中存储的对象会被gc回收。对象从不显示的释放。
¶java栈
- java虚拟机栈是线程私有的,每个线程都会创建一个自己的虚拟机栈。
- java栈中存储有栈帧,栈帧存储了方法的局部变量表(local variables),操作数栈,动态连接和方法返回地址。
- 栈帧除了入栈帧和出栈帧外,从不直接操作,因此可以对帧进行堆分配。
- 局部变量表:
局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量,它是一个变量数组。
在Java程序编译为Class文件时,就在方法表的Code属性的max_locals数据项中确定了该方法需要分配的最大局部变量表的容量。
单个局部变量能存储一个 boolean, byte, char, short, int,float, reference, 或者 returnAddress类型。一对局部变量能存储long或者double类型
第一个局部变量的索引为0,当一个整数小于当前本地变量数组的大小(差值在0到1之间),那这个整数才能作为这个局部变量数组的索引。
long或double类型的值占用两个连续的局部变量。java虚拟机可以不需要索引值n为偶数(索引值为偶数因为long或double占用两个连续的局部变量),因为long或double的值可以不用8字节对齐,可以将值所占空间根据大小进行压缩。
当调用方法时,java虚拟机使用局部变量用来传递参数。在调用方法时,以本地变量索引为0开始,通过连续的本地变量数组传递参数。在实例方法调用时,本地变量0总是用来传递对象引用(this),其他的参数从本地变量索引为1开始,通过连续的本地变量数组传递。 - 操作数栈:
操作数栈是一个LIFO栈(后进先出),在Java程序编译为Class文件时,就在方法表的Code属性的max stacks数据项中确定了该方法需要分配的操作数栈的容量。
当栈帧被创建时操作数栈是空的。java虚拟机提供指令从本地变量或字段中加载常量或者值到操作数栈中。
其他的虚拟机指令将从操作数栈中获取操作数,对其进行操作,并将返回的结果推入操作数栈中。操作数栈也被用来准备传递给方法的参数和接收方法结果。 - 动态连接:
每个帧都包含对当前方法类型的运行时常量的引用,以支持方法代码的动态连接。
一个方法的class文件代码引用被调用的方法和被访问的本地变量需要用符号引用来进行。
动态连接将符号方法引用翻译成具体方法引用,根据需要加载类以解析尚未定义的符号,并将变量访问转换为与这些变量的运行时位置相关联的存储结构中的适当偏移量。
这种方法和变量的后期绑定使得方法使用的其他类中的更改不太可能破坏此代码。
¶本地方法栈
- 本地方法栈又称为"C栈",它是用来支持用c/c++编写的本地方法。
- 当java虚拟机使用本地方法时,就需要使用本地方法栈来将本地方法压栈。
- java栈是java虚拟机的实现,不能被用来加载本地方法。
- 如果本地方法被用,当每个线程被创建时本地方法栈将被分配到每个线程。
- 如果本地方法栈大小被固定,则在创建本地方法栈时,可以独立选择每个本地方法栈的大小。
- 如果计算出线程需要本地方法栈比被允许的还要大,会出现StackOverflowError栈溢出异常。
- 如果本地方法栈能被动态扩展,但是可利用的内存不足,则会出现OutOfMemoryError内存溢出异常。
¶java内存模型
¶程序计数器
- java虚拟机支持同时执行许多线程。每个java虚拟机线程有自己的程序计数器。每个java虚拟机线程都在执行当前线程的方法。
- 如果不是native方法,这个程序计数器将会存储当前被执行的java虚拟机指令的地址;如果是native方法,java虚拟机的程序计数器会未定义。
- java虚拟机的程序计数器会足够的大,来存储returnAddress或者native指针。