JVM
JVM内存区域划分
线程共享
-
方法区
类信息、常量、静态变量、即时编译器编译后的代码。
方法区包含运行时常量池,存放编译器生成的字面量和符号引用。
方法区可扩展,可能OutOfMemoryError。
- 堆:
新生代:eden区、survivor from、survivor to;minorGc区域。
老生代:FullGc区域。
超过Xms内存时,抛出 OutOfMemoryError。
线程独享
-
Pc寄存器 存储当前线程正在执行的jvm指令地址,本地方法undifined,不会内存溢出。
-
Java虚拟机栈
保存栈帧,顶部为当前栈帧。栈的深度不够,如多次递归,会出现stackOverflowError。可动态扩展,无法申请更多内存时,初夏OutOfMemoryError.
栈帧保存如下内容
局部变量:方法参数和方法内部定义的局部变量
操作数栈
动态链接 :每个栈帧包含一个指向运行时常量池中该栈帧所属方法 的引用,持有这个引用是为了支持方法调用过程中的动态链接。
返回地址
-
本地方法栈保存虚拟机使用的native方法。同样可能出现 StackOverflowError和 OutOfMemoryError。
垃圾回收
垃圾判定算法
-
引用计数法
对象中添加一个引用计数器,有引用时加1,引用失效时减1,由于存在循环引用,java不使用。
-
可达性分析
从GC Roots为起点,向下搜索引用链中的对象。当某个对象与任何一个GC Roots 都无引用链想连时,标记为不可达。
可作为GC Roots的对象:
- 虚拟机栈
- 方法区的类属性引用的对象
- 方法区常量引用的对象
- 本地方法栈中引用的对象
垃圾回收算法
-
标记清除法
先用可达性分析标记出要回收的对象,再清除。不使用,内存不连续。
-
复制算法
内存分块,一块满了之后,将活着的对象复制到另外一块的连续空间,并清空。新生代使用此算法。
-
标记整理算法
使用标记清除算法之后,将存活的对象向一端移动,并更新引用其对象的指针。
垃圾收集器
-
SerialGC
单线程垃圾收集器。client模式新生代下默认gc。
-
ParNewGC
新生代GC实现,是SerialGC的多线程版本。
-
ParallelGC
server模式下jdk8默认模式,关注吞吐量。
-
CmsGC (Concurrent Mark Sweep)
基于 标记清除算法,并发执行,占用cpu资源较高。用于老年代。
-
G1GC
可预测stop。
类加载过程
类加载经过了加载、链接、初始化三个过程。
加载
将字节码从.class/jar/网络数据源中读到JVM中,并映射成JVM认可的数据结构,class对象。
此阶段用到了类加载器,可以自定义。
链接
-
验证
验证字节码是否符合jvm规范,防止恶意信息进入jvm。
-
准备
创建类和接口中的static变量,并初始化静态变量初始值。
-
解析
将常量池中的符号引用替换为直接引用。
初始化
执行类的初始化,包括静态字段赋值,静态代码块的执行。父类初始化优先于子类。
双亲委派模型
当类加载器试图加载某个类型时,尽量将这个任务代理给当前加载器的父类加载器。使用双亲委派模型的目的是,尽量避免重复加载java类型。
JVM工具
jps
查看jvm进程。-l 输出主类全名和执行路径,-v 输出jvm参数。
jstat 查看gc内存情况
jconsole 图形化工具
jinfo 查看虚拟机各项参数
jmap 生成堆转储快照
jstack 生成虚拟机当前线程快照
JVM 参数调优
Xms
Xmx
NewRadio
SuvivorRadio
对象的访问
java程序需要通过栈的reference来操作堆上的具体对象。主流的访问方式,由句柄方式和直接指针方式。
句柄访问
java堆中会划出一块区域作为句柄池,栈的reference中存储的是对象的句柄地址。句柄中包含了对象的实例数据和类型数据的地址信息。其中类型数据指针指向方法区,实例数据指针指向堆中的对象实例数据。
直接指针
reference指向堆中的对象实例数据,其中包含指向方法区的对象类型数据指针。
目前的hotspot采用直接指针,好处是访问快,缺点是回收要改变栈中的reference指针的指向。