JAVA的垃圾回收原理

    xiaoxiao2021-03-26  6

    JAVA的垃圾回收原理

    今天读到java的垃圾回收原理,觉得循序渐进的理解过程很有意思,就记录下来以备后用。主要分以下几个环节理解:

    最便于理解的基本原理的讲解提高效率的改进方法降低开销的附加方法进一步降低开销的自适应方法

    最便于理解的基本原理的讲解

    垃圾回收是对堆内不再被引用的对象所占内存空间的回收操作。所以判断是不是垃圾,就是判断对象是否还有引用。

    那么如果给每个对象准备一个计数器,来记录其上的引用个数,每增加一个引用,计数器加1,每减少一个引用,计数器减1(减到0为止),在回收的时候,遍历所有对象,对计数器为0的对象的内存进行回收即可。

    这样非常便于理解,但是遍历堆中的所有对象效率很低,另外还有个致命的问题,如果出现对象间的循环引用,当外部对他们的引用消失时,他们就应该被回收,可是他们的计数器却都不为0,这就出现了无法回收的内存,容易导致内存泄露。

    提高效率的改进方法

    从堆栈中的一个引用出发,找到它引用的对象,再找到这个对象包含的引用,反复进行,直到遍历完所有引用,就能找到所有不是垃圾的对象,把这些对象复制到新堆中,同时更新他们的引用指向新堆的内存地址,最后再把旧的堆整个回收,这样就不会出现循环引用无法回收的问题,而且复制后堆中的地址是连续的,不会出现碎片。

    这种方法叫做“停止-复制 ”,回收时程序会暂停。停止-复制 的效率提高很多,但它的最大开销是复制的过程。

    降低开销的附加方法

    内存分配以块为单位,有的对象很大,单个对象就会占用一个块,如果对这样的大对象进行复制,开销大且并没有实际意义。

    为了避免对块的无意义的复制,给每个块做个标记,标记它是否在用,遍历引用时,如果发现的是小对象,则复制到新块,回收结束后对新块进行整理。如果发现的是大对象,则对块做标记,不需要复制,这样就减少了复制的开销。

    进一步降低开销的自适应方法

    如果内存里并没有多少垃圾,进行一次停止-复制 就会白白消耗很多资源。为了避免在没有垃圾时的停止-复制,还有种方法叫做“标记-清扫 ”。在遍历引用发现对象时,给对象设置一个标记,当遍历结束时,没有任何标记的对象即为垃圾,会被全部清理。

    这种清理不会复制,因此清理后的区域会出现碎片,只能在垃圾很少甚至没有时使用,所以它应该和停止-复制 结合起来使用,当对象都比较稳定时,进行标记-清扫 ,当发现大量碎片时,进行停止-复制 ,这就是自适应 技术。

    转载请注明原文地址: https://ju.6miu.com/read-600124.html

    最新回复(0)