文章目录
类加载过程
类变量值在这里被指派,静态代码块在这里执行。
将字节码文件加载到以下即将介绍的运行时数据区里的方法区[或叫永久代]中
运行时数据区
- 方法区【永久代】
JDK1.8之后被元数据替换,并且元数据不在存在于JVM中,而是存在直接内存中,但是像一些常量池等直接放在堆中
移出的原因?
1.hotspot在1.8之后跟其他的jvm[JRockit]合并,但是JRockit并没有永久代或者方法区
2.原来的方法区的大小受限于jvm的大小,也就是加载的类数量有限,如果加载的类信息太多,会报oom。 - heap
堆一般存放对象,数组。是垃圾回收器管理的主要区域。
Java世界里基本所有的对象都在堆中分配 ,特殊情况是 经过逃逸分析后没有逃逸出去的 - pc计数器
读取指令,记录当前线程的执行位置 - 虚拟机栈
一般是由栈帧组成,是线程私有的 - 本地方法栈
是线程私有的
执行引擎过程
通过执行引擎跟本地方法接口JNI以及本地方法链接库来执行。
这里需要注意,只有热点代码才需要JIT编译,因为编译效率高,重复的代码才由JIT编译的价值。
逃逸分析也是在此处进行分析。
逃逸状态分为以下几种:
- 全局逃逸
- 参数逃逸
- 没有逃逸
没有逃逸的时候,进行优化
- 锁消除
- 栈上分配,虚拟机栈生成对象,避免GC
- 标量替换,把对象 直接变成基础类型和对象引用
加载以及执行过程:
1.加载字节码文件到方法区或者永久代。
2.线程的PC计数器指向字节码文件的指令。
3.每个字节指令由1个字节的操作码和1字节的操作数组成。
4.java执行引擎执行每个字节指令,解释器,然后调用本地方法接口,使用本地方法。
虚拟机栈
本地方法栈
PC计数器
堆空间结构
过程:
1.先进入Eden区,然后进行minorGC的时候,将Eden和From一起标记复制到To,然后清空Eden和From,变换From和To
2.下次MinorGC的时候,复制一次,age+1;
3.到达设定的age,搬运到老年代。
这里有一个老年代担保机制:说白了就是老年代出来担保说我自己空间足够放新生代来的。
但是仍旧有一个大前提:大对象直接放到老年代。
担保机制的目的:避免重复进行FullGC—》stop the world
担保机制 有一老一新:
老的担保机制:
1.先判断新生代所有对象空间是否大于老年代所剩余连续的空间
2.如果老年代够用,那没事minorGC。如果不够用,看看是否允许担保失败:
a.如果允许失败,那么判断老年代的最大可用的连续空间跟历次晋升到老年代对象的平均大小。如果够用,那么直接进行minorGC,如果不够用,那就直接进行FullGC
b.如果没有开启,直接FullGC
新的担保机制
1.判断新生代所有对象空间或者历次晋升到老年代对象的平均大小跟老年代能用的连续空间大小。
a.如果够用:直接MinorGC。
b.如果不够用:直接FullGC
担保机制有好也有坏:
**好处:**能够避免重复FullGC
**缺点:**如果是大对象,那么会重复进入FullGC。所以jvm直接设定大对象直接进入老年代。
垃圾收集器
- 这里需要注意的:由于历史原因,Parallel scavenge 跟parallel old是同个公司的,然后cms和Parallel old 是属于同个时期的竞品,所以Parallel scavenge只适配 serial old 和Parallel old。
- G1的垃圾回收算法:从局部来说是标记-复制,但是从整体来说就是标记-整理。
- 只有CMS用了标记-清除算法
serial/serial old
都是单线程
ParNew /Serial Old
Parallel Scavenge/Parallel Old
- Parallel Scavange 相比较于ParNew old 注重于 高吞吐量和GC自适应调节策略【参数自动调节】
CMS
- 浮动垃圾:并发标记的时候,用户线程产生的垃圾
- 三色标记法:一开始的引用断了,但是标记完,又重新建立引用==》导致本来是垃圾的,现在又不是垃圾了。解决方法:增量更新
G1
- 并发标记同样会产生CMS的三色标记产生的问题,但是这里的解决方法是:利用快照,再重新扫描一次。
- 设置 MaxGCPauseMills 设置停顿时间
- 维护一个GC优先列表,优先选择回收价值最大的Region