一、java虚拟机发展
- Sun Classic VM
(商用,纯解释器,性能差)
- Exact VM
- (准确式内存管理,编译器+解释器,
- 在Solaris平台发布(windows和linux没有发布),
- 初步具备高性能虚拟机的特性)
- HostSport
- 设计之初并非为java开发
- 继承了sun classic vm和exact的优点
- 热点代码探测技术,性能高,代码优化技术
- KVM
- 嵌入式的虚拟机
- 简单,轻量级,高度可移植
- 手机平台运行
- JRockit
- 快
- 专注服务器端应用
- 垃圾收集器+服务套件
- 诊断内存泄露问题
- J9(IBM公司)
- 类似于HotSport
- 多用途的虚拟机
- Azul VM Liquid VM
- 专用虚拟机,性能超强
- Taobao VM
二、内存管理
2.1线程独占区:
每个线程都有自己的虚拟机栈/本地方法栈/程序计数器
2.1.1 程序计数器:
- 当前线程所执行的字节码指令的行号指示器;
- 如果线程执行java方法,计数器记录–正在长记性的jvm字节码指令地址
- 如果线程执行native方法,计数器值为undefined
tips: 为什么要记录正在执行的指令的行号?
因为cpu按时间片执行,若当前指令没有执行完,时间片用完线程需要切换之后,做上下文恢复。
2.1.2 虚拟机栈
描述java方法执行的动态内存模型
存储当前线程运行方法所需的数据,指令,返回地址;
作为一个栈,栈内进出的基本单元是栈帧。
包含:栈帧,局部变量表,大小
栈帧
- 每个方法执行,都会创建一个栈帧,伴随着方法从创建到执行完成。用于存储局部变量表,操作数栈,动态链接,方法出口。
动态链接
what?
编译成.class字节码文件之后,只是生成了jvm所认知的逻辑地址,但是交于操作系统去执行时候,需要找到真实物理地址,所以需要将各个对象逻辑地址绑定到真实的物理地址,在运行时动态绑定的过程即为动态链接;
动态链接作用?
运行时来决定来调用哪个方法;
动态链接为什么在栈帧里面?
因为方法不执行的时候是没有必要解析的,
比如接口有n个实现类,运行时只是个符号引用,真正在调用方法时候才会去常量池找到真正的实例;
出口:
返回地址,方法执行完,需要出栈;
正常就需要return
异常需要throw error。
局部变量表
- 存放编译期可知的各种基本数据类型,引用类型,returnAddress类型
- 局部变量表的内从空间在编译期完成分配,当进入一个方法时,这个方法需要在栈帧中分配多少内存是固定的,运行期间不会改变
嵌套方法实际是多个栈帧
2.1.3 本地方法栈
与虚拟栈很类似(Hotspot不区分这两个栈)
为虚拟机执行native方法内存模型
本地方法:没有实现类,是其他语言实现的;
2.2 线程共享区域:
所有线程共享此区域
2.2.1 堆
存放对象实例
垃圾收集器管理的主要区域
区域:新生代,老年代,Eden空间
-Xmx -Xms 动态指定堆大小
2.2.2 方法区
-
存储虚拟机加载的类信息,常量,静态常量,即时编译器编译后的代码等数据
- 类信息:类的版本,字段,方法,接口
- 运行时常量
- 静态变量
- JIT
- 运行时常量池
- 存放各种字面量和符号引用 (int a =1),1是字面量,a是符号引用;
- 常量池里面不仅仅存储了常量,符号引用包含了类的名称和描述符,接口的名称,接口名,字段名,方法的名称及描述符,权限描述符等
- 常量池内放着类运行所需要的所有的东西;
-
方法区和永久代
- 使用永久代的方式来实现方法区,方法区是规范,永久代是实现
- jdk1.8 之后的元空间与永久代的地位是相等的,也是对方法区的一种实现;
-
垃圾回收在方法区一般不回收
-
异常–outofMemory
2.3 内存模型
关于meta Space
设计meta Space是为了规避永久代会溢出的问题,meta Space类似ArrayList可自动扩容;
但是自动扩容堆外内存不是越大越好;
2.4 栈+堆+方法区的交互关系