问题
- JVM垃圾回收机制
- GC发生在JVM哪部分
- 有几种GC,它们的算法是什么?
JVM体系结构
image.png
GC发生在JVM哪部分?
发生堆和方法区
主要发生在堆中
,堆区由所有线程共享,在虚拟机启动时创建。堆区主要用于存放对象实例及数组,所有new出来的对象都存储在该区域。
少部分发生在永久代
永久代的垃圾回收主要回收两部分内容:废弃常量
和无用的类
。
回收废弃永久代数据与回收Java堆中的对象非常相似。以常量池中字面量的回收为例,若字符串“abc”已经进入常量池中,但当前系统没有任何String对象引用常量池中的“abc”常量,也没有其他地方引用该字面量,若发生内存回收,且必要的话,该“abc”就会被系统清理出常量池。常量池中其他的类(接口)、方法、字段的符号引用与此类似。
无用的类需要满足3个条件:
(1)该类所有的实例都已经被回收,即Java堆中不存在该类的任何实例;
(2)加载该类的ClassLoader已经被回收;
(3)该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
jvm虚拟栈,本地方法栈,程序计数器不需要进行垃圾回收,因为他们的生命周期是和线程同步的,随着线程的销毁,他们占用的内存会自动释放。所以,只有方法区和堆区需要进行垃圾回收,回收的对象就是那些不存在任何引用的对象。
堆中内存分布:
针对于分代收集算法来定义分为新生代和老年代
其实新生代和老年代就是针对于对象做分区存储,更便于回收等等
堆大小 = 新生代 老年代。默认下,新生代 ( Young ) = 1/3 的堆空间大小,老年代 ( Old ) = 2/3 的堆空间大小
新生代又分为Eden和Survivor两个区。加上老年代就这三个区。数据会首先分配到Eden区 当中(当然也有特殊情况,如果是大对象那么会直接放入到老年代(大对象是指需要大量连续内存空间的java对象)。),当Eden没有足够空间的时候就会 触发jvm发起一次Minor GC。如果对象经过一次Minor GC还存活,并且又能被Survivor空间接受,那么将被移动到Survivor空 间当中。并将其年龄设为1,对象在Survivor每熬过一次Minor GC,年龄就加1,当年龄达到一定的程度(默认为15)时,就会被晋升到老年代 中了,当然晋升老年代的年龄是可以设置的。
为什么要进行分代?
隔离存活周期长的和短的对象,快速回收大量短存活周期对象。
新生代使用的GC算法
- 引用计数
已淘汰
- 复制算法
复制算法
老年代使用的GC算法
- 标记清除
image.png
- 标记压缩(对比普通标记清楚,它将需要清除的移动到一块连续的内存区域,清除的时候不会造成内存碎片)
image.png
- 标记清除压缩
标记清除,标记压缩结合使用
,先多次进行标记清除
,产生许多内存碎片,然后对碎片清理
(多次FULL GC之后再压缩),相对标记压缩减少了压缩次数
减少了许多移动成本
GC算法(引用计数/复制/标清/标整)是内存回收的方法论,垃圾收集器就是算法落地实现。
七大垃圾回收器