JAVA内存模型
线程私有:虚拟机栈,本地方法栈,程序计数器
线程共享:方法区,堆
程序计数器
当前线程所执行的字节码的行号指示器。
如果线程执行的是Java方法,则这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果执行的是Native方法,这个计数器值应为空(Undefined)
虚拟机栈
虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行时,Java虚拟机都会同步创建一个栈帧用于存储局部变量表,操作数栈,动态连接,方法出口等信息。每个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
本地方法栈
与虚拟机栈类似,不同的是本地方法栈记录的是Native方法。
Java堆
在虚拟机启动时自动创建,存放对象实例。Java世界中“⼏乎”所有的对象都在堆中分配,但是,随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致⼀些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。从jdk 1.7开始已经默认开启逃逸分析,如果某些⽅法中的对象引⽤没有被返回或者未被外⾯使⽤(也就是未逃逸出去),那么对象可以直接在栈上分配内存。
方法区
存放已经被虚拟机加载的类型信息,常量,静态变量,及时编译器编译后的代码缓存等数据。在jdk 1.8之前,方法区也叫永久代。
JDK 1.8 的时候,永久代被彻底移除了,取⽽代之是元空间,元空间使⽤的是直接内存。
为什么要用元空间取代方法区?
1.整个永久代有⼀个 JVM 本身设置固定⼤⼩上限,⽆法进⾏调整,⽽元空间使⽤的是直接内存,受本机可⽤内存的限制,虽然元空间仍旧可能溢出,但是⽐原来出现的⼏率会更⼩。
2. 元空间⾥⾯存放的是类的元数据,这样加载多少类的元数据就不由 MaxPermSize 控制了,⽽由系统的实际可⽤空间来控制,这样能加载的类就更多了。
3. 在 JDK8,合并 HotSpot 和 JRockit 的代码时, JRockit 从来没有⼀个叫永久代的东⻄, 合并之后就没有必要额外的设置这么⼀个永久代的地⽅了
运行时常量池
运行时常量池是方法区的一部分。
用来存放编译期生成的各种字面量与符号引用