感觉网上的资料是真的少,这个也是在听了马士兵老师的课之后又结合博客,深入理解JVM三,有了总结的路线。
一:垃圾回收针对堆区和方法区
二:怎样找到垃圾?
三:介绍新生代、老年代的模型(是部分垃圾回收器使用的模型)
四:清除垃圾算法?
五: Stop The World
一:垃圾回收针对堆区和方法区
hotspot在1.8之前叫永久代,1.8以及以后叫元数据空间。
hotspot1.8和和之前的变化:
1)移除了永久代(PermGen),替换为元空间(Metaspace);
2)永久代中的 class metadata 转移到了 native memory(本地内存,而不是虚拟机);
3)永久代中的 interned Strings 和 class static variables 转移到了 Java heap;(1.7就已经移除了)
4)永久代参数 (PermSize MaxPermSize) -> 元空间参数(MetaspaceSize MaxMetaspaceSize)
引用自《深入理解JVM三》:考虑到HotSpot未来的发展, 在JDK 6的时候HotSpot开发团队就有放弃永久代, 逐步改为采用本地内存(Native Memory) 来实现方法区的计划了[1], 到了JDK 7的HotSpot, 已经把原本放在永久代的字符串常量池、 静态变量等移出, 而到了JDK 8, 终于完全废弃了永久代的概念, 改用与JRockit、 J9一样在本地内存中实现的元空间(Metaspace) 来代替, 把JDK 7中永久代还剩余的内容(主要是类型信息) 全部移到元空间中。
二:怎样找到垃圾?
1.引用记数
给每个对象打上标记,被引用一次就cnt++,如果某个对象没有引用,cnt=0,那就可以清除,但是解决不了有向环类的相互引用。
2.Root Searching(根可达算法)
- 算法:标记根,从根开始搜索,根能到达的都不是垃圾,剩下的全是垃圾。
-
哪些是根:JVM stack(虚拟机栈栈帧里的引用对象)、方法区中类静态属性引用的变量、JNI指针指向的对象(就是Native方法)、虚拟机内部引用像NullPointerException和类加载器、Synchronized持有的对象。
三:介绍新生代、老年代的模型(是部分垃圾回收器使用的模型)
1.新生代、老年代介绍
- 垃圾回收区分为新生代、老年代。新生代又分为eden区,两个survivor。eden是干啥的?为啥要两个survivor?
- 注意图中默认内存大小的比例。
-
刚new的对象放在哪:
new一个对象默认是在eden区分配,如果对象比较大,eden放不下,直接放到老年代。 -
年轻代回收过程:
HotSpot虚拟机使用的是Copy算法,就是第一次进行YGC(年轻代垃圾回收,YGC不包含老年代)的时候。YGC首先把 eden该回收的回收,不该回收的放在survivor0区,age++。把eden清空,这样做可以减少eden区的空间碎片,并且效率比较高。
survivor0的放到survivor1,survivor1的放到survivor0,都age++。如果age>cnt,那就把他放到老年代。(说明这个玩意儿用了好久,之后我们不要轻易的回收它。cnt不同的垃圾回收器是不一样的)
这几个过程中,只要有放不下(内存)的都直接搁到老年代 -
老年代满了
就进行一次Full GC,Full GC包含YGC。
MinorGC=YGC MajorGC=FGC
2.JDK1.8当前默认垃圾回收器
是Parallel Scavenge(用于新生代的回收),Parallel Old(用于老年代的回收)。简称PSPO。没错是两个垃圾回收器!在JDK12不是开始收费了嘛,垃圾回收器换成了ZGC,不再用两个垃圾回收器,当然收费也贼高。ZGC就没有了新生代、老年代的概念。
四:垃圾清理算法
- Mark-Sweep(标记清除)
- Copying
- Mark-Compact(标记整理)
1. Mark-Sweep(标记清除)
该回收的就标记,不回收的就不管,这样做算法容易实现,复杂度也可以,但是会产生大量的碎片。
2.Cpoying算法
把空间分成两部分,一半永远都不使用,回收的时候,把回收的区域所有有用的对象都放到另一块干净的区域。然后擦除所有刚被回收的区域。这样做的好处是算法复杂度都可,但是浪费了大量的空间。
3.Mark-Compact(标记整理)
和标记清除的方法不一样,标记整理是把未回收对象集中起来放到一起。这样做有点耗时间。
五:Stop The World
很多人都遇到过,游戏每天半夜都要维护。还有12306每晚深夜都不能买票,这很可能就是(我可没说是,也是听来的例子)STW现象。
对于分代回收器像我们前面提到的Parallel Scavenge、Parallel Old,GC线程在进行工作的时候,所有!是所有其他线程全部停止,等着GC线程回收完毕才能继续运行,这就是STW。像ZGC(不是分代回收器),它没有STW现象。
·