Android开发Android进阶之路Android技术进阶

我的Android开发【分代收集算法】

2023-02-12  本文已影响0人  谁动了我的代码

为什么要采用分代收集算法?

分代收集理论

这个理论主要是建立在两个分代假说之上的:

这两个部分共同奠定了后面很多的垃圾收集器的基本设计原则:收集器应该将Java堆划分出不同的区域,然后将回收对象依据年龄分配到不同的区域进行存储,针对不同的区域,又进行不同的垃圾收集。

但在最后也还出现了一个问题,在进行一次只限于新生代区域的收集(Minor GC),但新生代中的对象完全有可能被老年代所引用的,为了找出该区域中的存活对象,就不得不在固定的GC Roots之外,再额外遍历整个老年代所有对象来确保可达性结果的正确性,反过来也是一样的。这种在理论上是可行的,但实际上会对内存回收带来很大的性能负担。

所以就有了第三条经验法则:

当在这之后再发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入GC Roots中进行扫描。

分代收集算法

就目前来讲,业界各种商业虚拟机堆内存的垃圾收集,基本上都采用了分代收集。可想而知,分代收集算法有多么重要。分代收集算法的思想是:

根据对象的存活周期,把内存分成多个区域,不同区域使用不同的回收算法回收对象。

堆内存结构 Java 把堆分成了"新生代"和"老年代",我们来看下图:

image

经过分代之后,垃圾回收可以分成以下几类:

由于执行Major GC的时候,也会伴随着一次Minor GC,可以认为,Major GC ≈ Full GC

下面我们来看一下对象是怎么分配到堆内存的。 对象在创建的时候,会先存放到伊甸园。当伊甸园满了之后,就会触发垃圾回收。这个回收的过程是:把伊甸园中的对象拷贝到From survivor或者是To survivor里面去。

比如说,第一次回收把对象拷贝到From survior里了,那么下一次回收就会把存活的对象从From survior拷贝到To survior,再下一次就会把To survior里的对象拷贝到From surivor,周而复始。那么不难发现,这个过程使用了复制算法,这也就是为什么新生代要有两个survior的原因。

那么对象每经历一次垃圾回收之后,那么还存活的话,他的年龄就会加一。当对象的年龄达到阈值的话(默认是15),就会晋升到老年代,老年代里的对象存活率是比较高的。

老年代一般是采用标记清除或者标记整理的思想进行回收。

注意

这里需要说明一下,这里的过程只是一个典型的分配流程。实际情况是存在例外的:

新建的对象不一定会分配到伊甸园,也有可能直接分配到老年代 这里主要分为两种场景:

对象不一定要达到年龄才进入老年代

垃圾回收的触发条件

新生代(Minor GC)触发条件

伊甸园空间不足,就会进行Minor GC回收新生代

老年代(Full GC)触发条件

建议垃圾回收器执行垃圾回收 -XX: +DisableExplicitGC 参数,忽略掉System.gc()的调用

image

上面的大概讲述了Android开发中的【理解分代收集算法】;有关更多的Android技术或者核心优化能力可参考《Android核心技术手册》点击即可进入。

总结

分代收集算法是根据对象的生命周期,把内存作分代,然后在分配对象的时候,不同生命周期的对象放在不同的代里面,不同的代上使用合适的回收算法进行回收,比方说,新生代里面的对象存活周期一般都比较短,每次垃圾回收的时候都会发现有大量的对象死去,所以新生代可以使用复制算法来完成垃圾收集。而老年代里的对象存活率比较高,所以就采用标记清除或者标记整理进行回收。

那么相比单纯的标记清除、标记整理、复制算法,分代带来了什么好处呢?

上一篇 下一篇

猜你喜欢

热点阅读