1.GC垃圾回收内容比较多.首先我们需要先知道它的垃圾回收的范围:
由上图可以知道GC的垃圾回收在方法区和堆,但99%的垃圾会在堆中产生!
2. 首先我们需要知道堆结构:
堆内存分为三个区域:
-
新生区(伊甸园区)young/new
-
养老区 old
-
永久区 perm
新生区:也可以再分为伊甸园区,和幸存区(有两个:from区和to区)
堆内存结构了解完后再来解释一下各个区的意思:
新生区
类:诞生和成长的地方,甚至死亡 -
伊甸园:所有的对象都是在这个区new来的
-
幸存区,也就是伊甸园区第一个GC回收后幸存下来的
老年区:从上面三个区追踪幸存下来的
永久区:这个区域常驻内存的.用来存放一个JDK自身携带的Class对象,Interface元数据,存储的是java运行时的一些环境.或类信息.这个区域不存在垃圾回收,关闭vm虚拟就会释放这个区域的内存.
3. GC回收机制的三种算法:
引用计数器法,复制算法,(标记清除压缩算法)
(1)引用计数器法:
计算每个对象的引用次数,清除无引用的对象,如图中灰色的对象C.
(2)复制算法
如果说幸存区中from 和to都有对象存在,那么两个区就会有一个区将里面的东西复制给另外一个区,以保证两个区中有一个区的时空的就定为to区
当一个对象经历了15次GC都还没有死就会进入养老区:-XXMaxTenuringThreshold = 15;通过这个参数可以设定进入老年代的时间,根据程序整体架构去进行调整。
分析:
**解析:**图中Eden区的存活下来的对象会复制到幸存区,幸存区有的对象也会复制到同一个区,这个区就变为from区,留下另一个幸存区to区为空.经过15次轻GC回收后存活下来的对象进入养老区.其他均被清除掉
上文中提到过轻GC,自然还会有一个重GC,那就是当新生区幸存区,养老区内存都满了之后,触发一次重GC,将三个区没引用到的对象清除出去.
- 好处:没有内存的碎片
- 坏处:浪费了一个幸存区的空间:多了一半空间(to)永远是空的,假设对象100%存活(极端问情况)
- 复制算法最佳使用场景:对象存货都较低的时候:新生区
(3)标记清除算法
缺点:两次扫描,严重浪费时间,会产生内存碎片,
优点:不需要额外的空间
解决问题:标记压缩,再优化!防止内存碎片产生,再次扫面,向一段的移动存活的对象,多了一次的移动成本
本质就是不断再优化。
标记清除压缩:
先标记清除几次,在进行压缩
总结:
内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法>标记清除算法
内存利用率:标记压缩算法=标记清除算法>复制算法
思考一个问题:难道没有最优算法吗?
答案:没有最好的算法,但是只有最合适的.依据场景来定.----->GC:分代收集算法
年轻代:存活率低,利用复制算法最好的
老年代:存活率高,区域大.利用标记清除(内存碎片不是太多的情况下),+标记压缩混合实现
-
轻GC和重GC分别在什么时候发生?
轻GC在新生代内存满了的时候,也就是伊甸园区,和两个幸存区都满了之后,会触发一次轻GC,这个时候会将伊甸园区99%的对象清理掉,还有少部分的幸存区的对象。
重GC在新生代,老年代的内存都满了之后,会触发一次重GC,重GC下手是很重的