Java虚拟机底层结构
1.类加载器(Class Loader): 装载编译后的字节码,并加载到运行时数据区
2.运行时数据区(Runtime Data Area)
堆(Heap): 通过 new 创建的对象, ...(所有线程共享)
方法区(Method Area): 常量+静态变量+类信息 (所有线程共享)
虚拟机栈(VM Stack): 栈帧(stack frame)
程序计数器(Program Counter Register): 记录所属线程所执行的字节码的行号(如 0:iconst_1 中的0)
本地方法栈(Native Method Stack): native 方法
3.执行引擎(Execution Engine): 执行字节码, 修改程序计数器值
栈帧(stack frame)
(1)局部变量表(Local Variable Table): 存放方法参数和方法内部定义的局部变量
(2)操作数栈(Operand Stack): 用于计算的临时数据存储区
(3)动态链接(Dynamic Linking): 将符号引用转换为直接引用
符号引用(Symbolic References): 如 invokevirtual #4 中的 #
(4)返回地址(Return Address): 返回到方法被调用的位置
代码
public class Math
{
public int compute() //一个方法对应一块栈帧内存区域
{
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
}
public static void main(String[] args)
{
Math math = new Math();
math.compute();
Math math2 = new Math();
math2.compute();
}
}
反编译
cd /d E:\eclipse-neon\workspace\Test\src\com\icss\ui
javap -c -verbose Math > Math.txt
部分
Compiled from "Math.java"
public class com.icss.ui.Math extends java.lang.Object
Constant pool:
const #1 = Method#5.#16;// java/lang/Object."":()V
const #2 = class#17;// com/icss/ui/Math
const #3 = Method#2.#16;// com/icss/ui/Math."":()V
const #4 = Method#2.#18;// com/icss/ui/Math.compute:()I
... ...
{
public com.icss.ui.Math();
Code:
0:aload_0
1:invokespecial#1; //Method java/lang/Object."":()V
4:return
public int compute();
Code:
0:iconst_1//将int类型常量1压入操作数栈
1:istore_1//将int类型值存入局部变量1
2:iconst_2
3:istore_2
4:iload_1//从局部变量1中装载int类型值
5:iload_2
6:iadd//执行int类型的加法
7:bipush10//将1个8位带符号整数(10)压入栈
9:imul//执行int类型的乘法
10:istore_3
11:iload_3
12:ireturn
public static void main(java.lang.String[]);
Code:
0:new#2; //class com/icss/ui/Math
3:dup
4:invokespecial#3; //Method "":()V
7:astore_1
8:aload_1
9:invokevirtual#4; //Method compute:()I
12:pop
13:new#2; //class com/icss/ui/Math
16:dup
17:invokespecial#3; //Method "":()V
20:astore_2
21:aload_2
22:invokevirtual#4; //Method compute:()I
25:pop
26:return
}
Object在堆中的基本内存结构
(1)Object Header(对象头)
(2)Instance data(实例数据)
(3)Padding(对齐填充, 保证对象是8个字节的整数倍)
Object Header (对象头)
(1)Mark Word (标记字段)
存储对象自身运行时数据:哈希值,GC分代年龄,锁状态标志,线程持有锁,偏向线程ID,偏向时间戳
(2)Klass Pointer (类型指针)
对象指向它的类元数据的指针,来确定这个对象是哪个类的实例
(3)数组长度 (只有数组对象才有)
堆(Heap)
年轻代(Young generation, 1/3):
Eden(8/10, 伊甸园), From Survivor(1/10), To Survivor(1/10)
老年代(Old generation, 2/3)
HotSpot–分代收集算法
所有实例在运行时最初都分配到 Eden 区,
当 Eden 区满后,执行引擎进行 Minor GC,回收年轻代,清除无效对象(失去引用的内存),
经过次 Minor GC 还存活的对象,会被移到 From 区,当 From 区满后,执行 Minor GC,
经过次 Minor GC 还存活的对象,会被移到 To 区,当 To 区满后,执行 Minor GC,
经过次 Minor GC 还存活的对象,会被移到 From 区,依次循环,
每进行一次 Minor GC 还存活的对象,其 GC分代年龄+1,
直到 分代年龄=15 后还存活的对象,会被移到 老年代,
当 Old 区满后,会进行 Full GC,当执行Full GC后空间仍然不足,
则抛出错误:java.lang.OutOfMemoryError: Java heap space,即 OOM(内存溢出)。
注: 对于一些较大的对象(即需要分配一块较大的连续内存空间),则是直接进入到老年代。
持久代(permanent generation), 也被称为方法区(Method Area)
stop-the-world(STW):
当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态,直到GC任务完成。
Minor GC: 清理年轻代,STW发生的时间非常短
Full GC: 清理整个堆空间和方法区,STW发生的时间比较长
Major GC: 清理老年代
JVM调优主要调整2个指标:
1.停顿时间: 垃圾收集器做垃圾回收中断应用执行的时间(STW)。
2.吞吐量: 垃圾收集的时间和总时间的占比: 1/(1+n), 吞吐量为 1-1/(1+n)。
GC机制实现机制
GC Roots: (tracing GC的“根集合”)
由堆外指向堆内的引用
一组必须活跃的引用
Java中可以作为GC Roots的对象:
(1)虚拟机栈(栈帧中的本地变量表)中引用的对象
(2)方法区中类静态属性引用的对象
(3)方法区中常量引用的对象
(4)本地方法栈中JNI(native方法)中引用的对象
GC会收集那些不是GC roots且没有被GC roots引用的对象
可达性分析法: --> 判定对象是否存活
基本思想: 通过一系列称为“GC Roots”的对象作为起始点,
从这些节点向下搜索,搜索所走过的路径称为引用链,
当一个对象到GC Roots没有任何引用链(即GC Roots到对象不可达)时,
则证明此对象是不可用的。
finalize()方法最终判定对象是否存活
前提: 对象在进行可达性分析后发现没有与GC Roots相连接的引用链
(1)第一次标记并进行一次筛选
筛选条件: 此对象是否有必要执行finalize()方法
当前对象没有覆盖finalize()方法,或者finalize()方法已被虚拟机调用过
-->没有必要执行-->第二次标记后,对象被回收
(2)第二次标记
如果这个对象被判定为有必要执行finalize()方法,那么该对象将会被放置在 F-Queue 队列中。
如果该对象重新与引用链上的任何一个对象建立了关联,那么移除 F-Queue 队列;
否则第二次标记后,对象被回收
注: 一个对象的finalize()方法最多只会被系统自动调用一次
finalize()的调用具有不确定行,只保证方法会调用,但不保证方法里的任务会被执行完
垃圾回收算法:
标记-清除算法
复制算法
标记-整理算法
分代收集算法
常见的将对象判定为可回收对象的情况:
(1)显示地将某个引用赋值为null或将已经指向某个对象的引用指向新的对象
(2)局部引用所指向的对象
(3)只有弱引用与其关联的对象
(4)无论什么情况下String对象都会被判定为可回收对象
四种引用状态:
1.强引用: StrongReference
垃圾回收器永远不会回收
如 Object obj = new Object();
内存空间不足,Java虚拟机抛出OutOfMemoryError错误
2.软引用: SoftReference
内存空间足够,垃圾回收器就不会回收它
内存空间不足,就会回收这些对象的内存
3.弱引用: WeakReference
一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存
4.虚引用: PhantomReference
虚引用并不会决定对象的生命周期
在任何时候都可能被垃圾回收器回收
虚引用必须和引用队列(ReferenceQueue)联合使用
GC(Garbage Collector, 垃圾收集器):
Serial GC
ParNew GC
Parallel Old GC(Parallel Compacting GC)
Concurrent Mark & Sweep GC (or “CMS”)
Garbage First (G1) GC