JVM内存模型

Posted 你是人间四月天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM内存模型相关的知识,希望对你有一定的参考价值。

引言

JVM是运行在操作系统之上,而JVM是要想了解JVM虚拟机运行的内幕,必须要先知道其内存模型
根据JVM规范,JVM内存共分为五块区域

本文围绕这个几个区域,剖析JVM运行时数据区

JVM运行时数据区

1.程序计数器

程序计数器是线程私有的,也就是意味着,每一个线程都有自己的一个独立程序计数器,里面记载着当前线程执行下一条字节码指令的行号,它的生命周期跟其对应的线程生命周期一样。
这里的程序计数器指的是JVM运行时指的下一条字节码的行号,跟CPU当中的程序计数器不一样,可以这么理解,这里的程序计数器是JVM指令级别的,而CPU内部的程序计数器是位于CPU的一个物理空间,通常我们把它称作——寄存器,它指向的是下一条CPU指令的内存地址,它是CPU指令级别的。
特点

  1. 线程私有
  2. 占用内存很小
  3. 在内存当中不可能出现OOM(OutOfMemory),所有对一这块区域也不存在垃圾回收这一说法
  4. 如果是在执行native方法,则是未指定值(undefined),因为程序计数器不负责本地方法栈。

2.JVM虚拟机栈

虚拟机栈也是线程私有的,一个线程对应着虚拟机栈里面一块区域。线程运行过程中,每个方法在执行的时候会创建一个栈帧,存储了局部变量,操作数,动态链接,方法返回地址。
每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。
如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError(递归调用)。
如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。

3.堆(Heap)

堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。
在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。
这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。

在默认的情况下,堆中各区域的大小占比
老年代:2/3的堆空间
年轻代:1/3的堆空间
eden区:8/10 的年轻代
survivor0: 1/10 的年轻代
survivor1:1/10的年轻代

4.本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot 虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError 和OutOfMemoryError异常。

5.方法区

所有方法线程共享的一块内存区域,用于存储已经被虚拟机加载的类信息,常量,静态变量等,永久代是它的一种实现。
这个区域的内存回收目标主要针对常量池的回收和堆类型的卸载。

常量池中存储编译器生成的各种字面量和符号引用。字面量就是Java中常量的意思。比如文本字符串,final修饰的常量等。方法引用则包括类和接口的全限定名,方法名和描述符,字段名和描述符等。

Java8版本及以后使用元空间 MetaSpace 替代方法区,元空间并不在 JVM中,而是使用本地内存。字符串常量和类文件中常量池放进了JVM的堆中
元空间两个参数:

  1. MetaSpaceSize:初始化元空间大小,控制发生GC阈值
  2. MaxMetaspaceSize : 限制元空间大小上限,防止异常占用过多物理内存

Java8 和 Java8以前


Java8 使用元空间 MetaSpace 替代方法区,元空间并不在 JVM中,而是使用本地内存。

扩展

1.对象的访问


通过句柄访问

直接访问

以上是关于JVM内存模型的主要内容,如果未能解决你的问题,请参考以下文章

JVM内存模型Java内存模型 和 Java对象模型

JVM:JVM内存模型

JVM内存模型详解

细说JVM内存模型

JVM优化系列-------[3丶JVM的内存模型]

两种内存模型——JVM vs 计算机