JVM 虚拟机 目录:
- JVM体系结构
- 程序计数器
- 虚拟机栈
- 本地方法栈
- 堆
- 方法区
JVM体系结构:
什么是JVM:
Java Virtual Machine: Java虚似机,用来保证Java语言跨平台。
Java虚似机可用看作是一台抽象的计算机,如同真实的计算机那样,它有自己的指令集以及各种运行时内存区域
Java虚似机与Java语言并没有必然的联系它只与特点的二进制文件格式(class文件格式所关联)
Java虚似机就是一个字节码编译器,它将字节码文件翻译成各个系统正确运行。
为什么要学习JVM
因为面试会问到,所以我们要去学习并且理解。
JVM内存结构:
程序计数器:
作用:保存当前执行指令的地址,一旦指令执行,程序计数器将更新到下一条指令
虚拟机栈:
每个线程运行时所需要的内存空间,成为虚拟机栈
每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
栈帧:
组成:局部变量表、操作数栈、动态链接、方法返回地址
局部变量表:存放局部变量的列表
一个局部变量可用保存类型为Boolean、byte、char、short、float、reference和return Address的数据
两个局部变量可以保存一个类型为long 和double的数据
局部变量使用索引来进行定位访问,第一个局部变量的索引值为0
操作数栈:
也称为操作栈,它是一个后进先出的栈
当一个方法刚刚开始执行时,其操作数栈是空的。
随着方法执行和字节码指令的执行,会从局部变量表或者对象实例的字段中复制常量或变量写入到操作数栈,在随着计算的进行将栈中元素出栈到局部变量表或者给方法调用者,也就是出栈/入栈操作
一个完整的方法执行期间往往包含多个这样出栈/入栈的过程。
简单理解,操作数栈是线程实际的操作台
动态链接:
简单的理解为指向运行时常量池的引用
在class文件里面,描述一个方法调用了其他方法,或者访问其成员变量是通过符号引用来表示的,动态链接的作用是讲些符号引用所表示的方法转换实际方法的直接引用。
方法返回地址:
方法调用的返回,包括正常返回(有返回值)和异常返回(无返回值),不同的返回类型有不同的指令
无论方法采用何种方法退出,在方法退出后都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在当前栈帧中保存一些信息,用来帮他恢复它的上层方法执行状态。
栈内存溢出
栈帧过多导致栈内存溢出
栈帧过大导致栈内存溢出
本地方法栈:
本地方法栈的功能和特点类似于虚拟机栈,也是线程私有的
不同的是:
本地方法栈服务的对象是JVM执行的native 方法,而虚拟机栈服务的是JVM执行的Java方法
如何去服务native方法呢
native方法使用什么语言实现?
字母组织像栈帧这种为了服务方法的数据结构?
虚似机规范并未给出强制规定,因此不同的虚似机实可以进行自由实现
堆
作用:
用于存放对象的内存区域
特点:
堆是被所有线程共享的一块内存区域,在虚似机启动时创建
堆的区域是用来存放对象实例的,因此也是垃圾收集器管理的主要区域
堆在逻辑上划分为“新生代”和“老年代”,新生代分为Eden区、ServivorFrom、ServivorTo 三个区
堆一般实现成大小是可扩展,使用“-Xms”与“-Xmx” 控制堆的最小与最大内存
堆内存溢出
错误提示:
java.lang.OutOfMemoryError:Java heap space
错误原因:
内存真不够,通过调整堆内存大小解决
存在死循环,通过修改代码解决
堆内存诊断
jps:查看当前系统中哪些Java进程
jmap 工具:查看堆内存占用情况(某一个时刻)
jmap -heap 进程Id
jconsole 工具:图形界面的,内置Java性能分析器,多功能的监测工具,可以连续监测
方法区
作用:存储每个类的结构
列如运行时常量池,字段和方法数据,以及方法和构造函数的代码,包括用于类和实例初始化以及接口初始化的特殊方法等
线程共享:所有线程都能访问这块内存数据,随虚似机或者GC而创建和销毁
线程独占:每个线程都会有它独占的空间,随线程生命周期而创建和销毁
方法区:
存储加载的类信息、常量、静态变量、JIT编译后的代码等数据
GCL:方法区存在垃圾回收,但回收效率低;
回收主要针对常量池的回收,和类型的卸载
当方法区无法满足内存需求时,报OOM
堆内存:
作用:唯一的目的就是存放对象实例,几乎所有的对象、数组都在这里存放
对于大多数应用来说,堆是JVM管理的内存中最大的一块内存区域,也是最容易OOM的区域
大多数JVM都将堆实现为大小可扩展的(通过-Xms、-Xms控制)
引用计数器算法:存在两个对象相互引用的问题
可达性分析算法:主流的商用程序语言(Java、C#)都是通过可达性分析算法来判定对象是否存活的
GC Roots :可以是1.虚拟机栈、2.方法中静态属性引用的对象;3、方法区中常用引用的对象;Native 方法引用的对象。
虚拟机栈:
线程中方法执行的模型,每个方法执行时,就会在虚拟机栈中创建一个栈帧,每个方法从调用到执行的过程,就对应着栈帧中从入栈到出栈的过程。包括(局部变量表、动态引用、操作数栈、返回值返回、main方法栈帧)
栈帧:虚拟机栈有由多个栈帧(Stack Fframe)组成,一个线程会执行一个或者多个方法,一个方法对应一个栈帧。