共计 1345 个字符,预计需要花费 4 分钟才能阅读完成。
jvm – 垃圾回收咱们晓得了哪些类是须要革除的,那在 java 虚拟机中,他有哪些垃圾收集算法呢?
标记 - 革除
标记 - 革除算法就是,先标记哪些对象是存活的,哪些对象是能够回收的,而后再把标记为可回收的对象革除掉。从上面的图能够看到,回收后,产生了大量的不间断的内存碎片,如果这个时候,有一个比拟大的对象进来,却没有一个间断的内存空间给他应用,又会触发一次垃圾收集动作。
复制算法
复制算法是通过两个内存空间,把一方存活的对象复制到另外一个内存空间上,而后再把本人的内存空间间接清理。
标记后,此时状况如下:
而后再把右边的存活对象复制到左边:
复制完后,再清理本人的内存空间:
左边的空间开始回收,再复制到坐标,如此往返。这样就能够让存活的对象严密的靠在一起,腾出了间断的内存空间。
毛病就是空间少了一半,这少了一半的空间用于复制存活的对象。然而在理论过程中,大部分的对象的存活工夫都十分短,也就是说这些对象都能够被回收的。比如说右边有 100M 空间,然而只有 1M 的对象是存活的,那咱们左边就不须要 100M 来寄存这个 1M 的存活对象。因而咱们的新生代是分成 3 个内存块的:Eden 空间、From Survivor 空间、To Survivor 空间,他们的默认比例是 8:1:1。也就是说,平时的时候有 Eden+Survivor=90M 能够应用,10M 用于寄存存活对象(假如 100M 空间)。这个算法在 jvm – 堆内存调配的对象优先在 Eden 调配中提过了。
标记 - 整顿
除了新生代,老年代的内存也要清理的,然而下面的算法并不适宜老年代。因为老年代对象的生命周期都比拟长,那就不能像新生代一样仅节约 10% 的内存空间,而是节约一半的内存空间。
标记 - 整顿与标记 - 革除都是先标记哪些对象存活,哪些对象能够回收,不同的是他并没有间接清理可回收的对象,而是先把存活的对象进行挪动,这样存活的对象就严密的靠在一起,最初才把垃圾回收掉。
回收前,存活对象是不间断的。
回收中,存活对象是间断的。
回收后,回收垃圾对象。
性能与优化
针对新生代,Minor GC 触发的起因就是新生代的 Eden 区满了,所以为了缩小 Minor GC,咱们新生代的内存空间不要太小。如果说咱们给新生代的内存曾经达到机器了极限了,那只能做集群了,把压力分担进来。
老年代的垃圾回收速度比新生代要慢 10 倍,所以咱们也要尽量减少产生 Full GC。
jvm – 堆内存调配中咱们提到了几种进入老年代的形式,咱们看看这些是怎么解决的:
- 大对象间接进入老年代:这个没方法优化,总不能调大对象大小吧,那这些大对象在新生代的复制就会很慢了。
- 长期存活的对象将进入老年代: 年龄的减少,是每次 Minor GC 的时候,所以咱们能够缩小 Minor GC(这个办法下面提到了),这样年龄就不会始终减少。
- 动静年龄判断: 有一个重要的条件就是在 Survivor 空间中雷同年龄所有对象大小的总和大于 Survivor 空间的一半,所以要加大新生代的内存空间。
- 空间调配担保: 这外面有一个条件是 Minor GC 后,Survivor 空间放不下的就寄存到老年代,为了让存活不到老年代,咱们能够加大 Survivor 空间。
下面的办法,既有加大新生代的内存空间,也有加大 Survivor 空间,实时上,怎么优化,须要依据咱们的理论场景来看,JVM 的优化并没有银弹。