JVM调优那些事(一)垃圾扫描与清除

前言

这篇文章是JVM调优系列的第一篇,主要讲关于内存垃圾的内容。

JVM调优是指对JVM性能的调优。而制约JVM运行速度的,就是可运行的内存空间,如果内存空间被大量的垃圾占据,那么JVM的运行速度就会不可避免的降低。

那么什么是垃圾呢?

在JVM中,我们对内存垃圾的定义很简单:内存中没有引用指向的对象。

本文会介绍JVM是如何寻找垃圾的,并且介绍三种回收垃圾内存的机制。

垃圾标记方法

前面我们已经说过,所谓的垃圾就是没有引用指向的对象。那么JVM是用什么方法定位到这些垃圾的呢?

有下面这两种方法:

reference count

引用计数法。

就是对每个对象都追踪指向它们的引用数,如果引用数为0,就说明这个对象是内存垃圾了。

但是这种方法有个缺陷,就是没办法解决垃圾簇问题。

就是说,如果是好几个对象互相引用,但是这些对象作为整体没有被外部引用指向,那么这些实质上的内存垃圾就没办法被标记。

为了解决这个问题,出现了下面这种标记垃圾的方法。

root searching

根可达算法。

指从根对象开始扫描,所有可以被扫到的对象都被标记为存活对象,而扫不到的对象就是垃圾对象。

对扫到的对象一般是在该对象的header中打上一个标识,表示当前对象还是存活对象。

那么什么是根对象呢?主要由下面四种对象构成:

  1. main方法的栈帧中的对象。
  2. class文件中的静态变量
  3. 常量池中的对象
  4. JNI用到的对象

垃圾清除方法

既然已经知道哪些对象是垃圾了,就要将这些垃圾清除掉。

垃圾清除方法主要有下面三种:

mark-sweep

这种方法分为两个阶段,分别是标记(mark)阶段和清除(sweep)阶段。

其中,标记阶段就是上面提到的垃圾标记算法中的root searching方法。

而在清除阶段,垃圾收集器就会遍历堆内存,将内存中垃圾对象所占的内存回收。

在这里插入图片描述

这种垃圾清除算法是存在缺陷的:

  1. 产生内存碎片,回收的内存并不连续,难以管理。
  2. 产生了两次扫描,效率比较低。

copying

为了解决mark-sweep方法存在的问题,又出现了这种垃圾回收算法——copying

这种算法首先将内存分为大小相等的两块,每次只使用其中的一块。

当一块内存满了之后,就将还存活的对象copy到另外一块内存上,如此反复。

这种方法虽然避免了内存的碎片化,但同样由下面的问题:

  1. 造成可用内存的永久减半
  2. 由于存在复制操作,所以效率会比较低,只适用于存活对象比较少的时候

mark-compact

如果既不想造成内存碎片化,又不想浪费一半的内存空间,就要采用第三种垃圾回收算法——mark-compact算法。

这个方法同样分为两个阶段,标记(mark)阶段和压缩(compact)阶段。

其中标记阶段还是用root searching来标记存活对象。

而压缩阶段,则是把所有存活对象往内存开始端复制,从而可以规整出一大片连续可用的内存。在这里插入图片描述

这种垃圾清除算法也有缺陷,就是效率不高,因为也会发生两次扫描,还会发生内存复制。

总结

本文主要讲了JVM中寻找垃圾以及回收垃圾的具体机制

root searching成为当下可以选择的最优的垃圾寻找算法,而三种垃圾清除算法则各有优劣,需要根据具体情况加以选择。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值