文章目录
一、JVM内存模型
线程共享:
1.堆
2.方法区
线程私有:
1.虚拟机栈
2.本地方法栈
3.程序计数器
二、线程共享
1.方法区(Method Area)
虚拟机规范中将方法区看做是堆的逻辑部分,但是对于HotSpotJVM实现上,将堆和方法区分开,认为是两个不同的结构,方法区还有一个别名是Non-Heap(非堆)。
也可以理解new出来的都在堆里面,方法区里面放的是类的信息。
所以方法区可以看作是一块独立于Java堆的内存空间。
1.方法区主要存放的是Class,而堆中主要存放的是实例化的对象
2.方法区(Method Area)与Java堆一样,是各个线程共享的内存区域
3.方法区在JVM启动的时候被创建,并且它的实际的物理内存空间和Java堆一样都可以是不连续的。
4.方法区的大小跟堆空间一样,可以选择固定大小或者可扩展
5.方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutOfMemoryError:PermGen space(JDK7及之前)或者java.lang.OutOfMemoryError:Metaspace(JDK8及之后)
6.关闭JVM就会释放这个区域的内存
JDK1.7及之前,方法区是由永久代实现,使用JVM虚拟机内存;
JDK1.6及之前,字符串常量池、静态变量存放在永久代上;
JDK1.7及之后,字符串常量池、静态变量存放在堆中。
JDK1.8及之后,方法区是由元空间实现,使用物理机本地内存。
2.堆(Java Heap)
Java堆是Java虚拟机所管理的内存区域中最大的一块,用于存储对象实例以及数组。Java堆是垃圾收集器管理的主要区域,因此也被称为GC堆。在虚拟机启动时创建,被所有线程共享。
Java对象实例以及数组都在堆上分配。
三、线程私有
1.Java虚拟机栈(Java Virtual Machine Stacks)
虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。所以虚拟机栈是线程私有的,随着线程的创建而创建。
每一个被线程执行的方法,为该栈中的栈帧,即每个方法对应一个栈帧。(调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出。)
每个栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、动态链接、方法返回地址和附加信息。
2.本地方法栈(Native Method Stack)
与JVM Stack类似,但是本地方法栈用于执行Native方法。
3.程序计数器(Program Counter Register)
程序计数器是一块较小的内存区域,它保存了当前线程正在执行的字节码的地址。在线程切换时,程序计数器也发生相应的变化。