JVM的概念
- 虚拟机简介:
- JVM(Java Virtual Machine的简称。Java虚拟机)
- 虚拟机:指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。常见的虚拟机有:JVM、VMware、Virtual Box
- JVM与其他两个虚拟机的区别:
- WMware与Virtual Box是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器
- JVM则是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,其他的寄存器都进行了裁剪
JVM是一台被定制过的现实当中不存在的计算机
JVM运行时区域划分
- 线程私有
- 程序计数器
- 虚拟机栈:java方法内存模型
- 本地方法栈:native方法内存模型
- HotspotJVM中本地方法栈与虚拟机栈合二为一
- 线程共享
- 堆:所有对象实例与数组对象
- 方法区:已加载的类信息、静态变量、常量、即时编译器编译后的代码等数据
- 运行时常量池:方法区的一部分,字面量(字符串、final常量、基本数据类型的值)、符号引用(类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符)
GC相关
- 如何判断对象是否存活,引用计数法,无法解决循环引用问题(我只有你,你中有我)。给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已"死"。
Person p1 = new Person();
Person p2 = new Person();
p1.instance = p2;
p2.instance = p1;
p1 = p2 = null; //导致无用对象仍然判断存活而无法被回收
- 可达性分析算法:判断对象是否存活。: 通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径 称之为"引用链",当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。
- 哪些对象可作为GC Roots:
- 栈中引用的对象
- 类中静态变量、常量引用的对象
- JDK1.2关于引用的扩充
- 强引用:程序中普遍存在,类似于直接new称为强引用。对象被任意一个强引用指向,即便抛出OOM异常,也无法回收被强引用指向的对象
- 软引用:描述有用但不必须对象(缓存),SoftReference类描述软引用。若对象只被软引用指向,当前内存够用时不回收,如果即将抛出OOM异常时,一次性回收所有仅被软引用指向的对象
- 弱引用:WeakReference。仅被弱引用指向的对象,无论内存是否够用,当GC开始时,都会回收掉仅被弱引用指向的对象
- 虚引用:PhantomReference。虚引用完全不对对象的生存周期产生任何影响,也无法通过虚引用取得一个对象实例。当虚引用指向的对象被GC时,JVM会发回一个回收通知
- 对象的自我拯救finalize JDK1.9 @Deprecated
- 若对象所在的类覆写了finalize(),该对象的finalize()未被JVM调用过,JVM会调用此对象的finalize();该对象的finalize()被JVM调用过,此对象被标记位不再存活,可以进行GC。finalize()方法是对象逃脱死亡的最后一次机会。任何一个对象的 finalize()方法都只会被系统自动调用一次,如果相同的对象在逃脱一次后又面临一次回收,它的finalize()方法不会 被再次执行,因此第二段代码的自救行动失败。
- 若对象所在的类没有覆写了finalize(),此对象直接标记位不再存活,可以进行GC
- 垃圾回收算法
- 将堆空间分为新生代和老年代,对象默认在新生代产生
- 新生代对象“朝生夕死”,新生代对象的存活率很低(<=2%)
- java采用分代回收算法,新生代采用复制算法,老年代采用标记整理算法
- 新生代GC比老年代的GC速度快10倍以上,发生频率高的多
- 老年代不采用复制算法,是因为老年代对象存活率很高,若采用复制算法,复制开销远高于新生代,不适合复制算法
- -Xss:设置栈的大小(如:128k)
- -Xms:设置堆的最小值(如:10m)
- -Xmx:设置堆的最大值
- -Xmn:设置新生代内存大小
JMM
- volatile
- 可见性
- 禁止指令重排;volatile代码既不会提前也不会滞后,volatile代码前的所有代码一定全部执行完毕,volatile的所有代码一定还未开始