一、内存模型
JVM组成部分
-
首先通过类加载器(ClassLoader)会把 Java 代码转换成字节码
-
运行时数据区(Runtime Data Area)再把字节码加载到内存中,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。
JVM运行时数据区
二、各个部分探析
-
PC程序计数器
-
概念:是较小的内存空间,看做行号指示器,实现字节码指令的选择,分支,跳转,循环,异常处理,线程恢复等功能。每个线程启动,都会创建,是每个线程独有的,记载着线程当前运行的JAVA方法的地址;
-
特点:在Java虚拟机规范中唯一没有规定任何OutOfMemoryError 情况的区域。
-
问题:
- 1.为什么程序计数器不会OutOfMemoryError?
每个线程都会有一个私有的程序计数器,那么如果线程数很多的时候呢,也不会溢出吗?
理解:暂时有2个理解:①对于单线程,只需要少量的计数器就可以记录字节码 指令运行的地址,修改的也只是其中的值,并非需要申请新的空间;对于多线程,随着线程数的创建,pc计数器增加,但是线程数的开辟是有限的,所需的PC计数器的内存也是能满足的;②另一个解释是:书中这个意思就是针对单线程的来讲的,重在突出PC计数器的功能是修改计数器所指向的内容,故可以不需要大量空间;
-
2.为什么执行本地方法时,PC寄存器值为空?
native方法是通过调用系统指令来实现的,它不是java代码实现的,大部分用C/C++编写的,并未编译成字节码文件,native方法就由原生平台直接执行,并不需要理会抽象的JVM层面上的“pc寄存器”概念
https://www.cnblogs.com/datamining-bio/p/11143338.html
-
-
Java虚拟机栈
-
概念:每个方法执行时都会创建一个栈帧,用于存储局部变量表**(8大基本数据类型、对象引用类型)**、操作数栈、动态链接栈、方法出口等信息。过程伴随着栈入栈出的操作。执行Java方法。
-
特点——规定了两种异常:
① 如果线程请求的栈深度大于虚拟机允许的深度,抛出StackOverFlowError异常;
② 如果虚拟机可动态扩展,当扩展时无法申请到足够的内存,会抛出OutOfMemoryError异常。
-
**问题:**对象引用类型是什么?
类、接口、数组、枚举、注解、字符串,在堆中开辟空间存储后,需要在栈中开辟指向堆中对象的地址,称为引用类型。
https://gitbook.cn/books/5dc0be1fcc8f2b3cfc2f89e9/index.html
-
扩展:指针和引用的区别?
(1)引用在创建时必须初始化,指针可以不初始化,引用不可以为NULL,指针可以。
(2)不存在指向空值的引用,但是存在指向空值的指针。(3)引用初始化后不能被改变,指针可以改变所指的对象
-
-
本地方法栈
- 概念:与Java虚拟机栈作用相似,区别仅在于这个区域执行的是Native方法
- 特点:**同Java虚拟机一样,会抛出两种异常。
-
Java堆
- 概念:GC堆,
- 特点:线程共享,内存中最大,存放对象实例
- 注意:逃逸分析等技术使实例对象在堆上分配这个说法不是绝对。
-
方法区
- 功能:存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 特点:线程共享,无法满足内存分配需求时,抛出OutOfMemoryError异常
-
运行时常量区*池
概念:是方法区的一部分,存放编译期间生成的各种字面量和符号引用。
三、参考:
1.《深入理解JVM虚拟机》