什么是垃圾收集算法?
垃圾收集算法
常见垃圾收集算法
1.标记扫描算法
2。复制算法
3。标签压缩算法
4。分代垃圾收集算法
标记清除算法
标记清除算法在JVM运行时标记Java对象驻留的内存区域。由于Java对象是分布在内存中的,所以有些对象可以重用,有些则不能。在我们将内存标记为要回收后,我们会处理该内存一次。由此带来的一个问题是,回收后,内存空间分散在堆内存中。这些碎片化的内存空间将来会导致对象变大。该师不能进入。
复制算法
复制算法可以解决清除上述内容后出现大量碎片内存空间的问题。复制算法将整个内存空间划分为两个大小相等的区域。每使用一块内存,当该区域的内存令牌被删除时,剩余的对象就会被复制到另一个内存块中,这样就可以释放出一块连续的内存。空间,每次分配内存时,都可以移动堆顶的指针,按照堆顺序进行分配。
注意。这种算法浪费了大量的内存空间,而且每次实际可用空间都会减半,成本非常高。目前大多数商业虚拟机都使用这种算法进行垃圾收集,但它们已经过优化和改进。由于jvm运行时大多数对象的生存时间都很短,所以这类对象的生命周期一般都会涉及到线程的启动和死亡,基本没什么用处。所以后来jvm内存分区被重新分配,出现了新生代和老年代。新一代内存区域分为Eden区和Survivor区。这样,大部分对象创建都是先在Eden中分配,然后每次运行。 YGC可以将幸存的对象转移到Eden区的Survivor中。当达到一定的GC年龄后,就可以复制到老年代了。另外,老年代是年轻代内存分配的保证。如果年轻代无法分配,则通过分配的保障机制直接进入老年。这里的年轻代Survivor其实分为两种:幸存者和幸存者。这里的复制规则稍后详细讨论。
令牌排序算法
上面的复制算法看到内存需要分块,分为两块。当然,我们知道年轻代并没有完全分裂成两半,所以一半的内存仍然无法访问。对象是直接分配的,所以上面的年轻代的大小只占堆的很小一部分,通常是1/4或1/3。这样老年代就可以为年轻代提供保证,但是回收老年代的时候,采用一分为二的方式来分配内存,没有其他的内存保证。因此,复制算法不适合重用老年代内存。因此,老年代复用已经不再适合复制算法,于是出现了mark-collation算法,它与markup和clear类似,只是排序的过程需要将保存的对象移动到堆的一端,保证清空后内存仍被保留。连续性。
注:这里的年轻代采用的是Eden和Survivor方式。比例也可以自由实现,默认的Eden/survivor一般为8:1。它没有完全分成两半,但仍然可见。不知道块复制
收集代的算法
上面提到的算法在一些商业虚拟机中使用。 jvm综合了上述每种算法的优缺点,分代处理内存空间。分为年轻代和年老代,以及老版本的永久代。不同类型的回收算法用于不同的生成区域。因此,在年轻代中,如上所述,可以使用复制算法来复制Eden中的对象。去找幸存者,然后转向老一代。老年代通过标记和排序来保证栈空间的连续性。我们平时使用的Hotspot虚拟机的回收,是采用不同的垃圾收集器进行回收的,垃圾收集器使用了上面提到的几种回收算法。
“Stop The Word”
这里我们主要讲Stop The World。我想这就是Java虚拟机的垃圾回收功能。 STW表示jvm在收集垃圾时停止应用程序线程。因此,应用程序运行时会有短暂的暂停。我们称之为“停止世界”。为什么jvm需要Stop the World?前面提到,Java虚拟机通过根对象可达性分析来判断对象的存亡。在程序运行过程中,栈上的变量表一直在变化,因此jvm必须在某个时刻获取栈。如果想要获取某个时间点的对象快照,则需要短暂的停顿来完成冻结,设置根对象,然后完成引用可用性分析。
安全点和安全区
首先,热点jvm中有一个OopMap数据结构,用于准确存储对象的引用。无需每次都检查堆栈引用对象的位置。如果是 STW,jvm 会获取此处引用的报价进行分析。当然,JVM 不仅仅随机停止所有应用程序线程。它还要求程序到达这个安全点或安全区。在这些时刻或时间间隔,JVM 启动 STW 并挂起线程。这个安全点在JVM中也存在。选中,在线程执行期间提示安全点识别。当所有线程都被通知它们将到达安全挂起点时,jvm 将执行适当的垃圾收集。
了解了这些垃圾收集算法后,我们就可以分析每个分区的垃圾收集器在每个时期的特点。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网