Java虚拟机之垃圾回收

      内存作为程序运行时非常重要的一个系统资源,直接影响到程序的正常运行和程序性能。C/C++需要程序员显式地分配和释放内存,这不仅给程序员带来工作负担,而且还会给程序带来内存错误访问和泄露的安全隐患。Java的垃圾回收能够自动地管理内存,不仅提高了程序开发效率,而且保证了系统的安全性。

      Java的垃圾回收机制主要的任务有两个:1. 识别不再被使用的对象;2. 释放不再被使用对象的内存,并归还给程序。

        为了识别不再被使用的对象,Java有两种标记垃圾的方法:
1. 计数法:
        每个对象分配一个计数器,用来区分活跃对象和不再使用对象。对象每被引用一次,其计数器加1,引用消失,其计数器减1。计数器为0时,对象被回收,其引用的所有对象的计数器都减1。
      计数法的优势是很快被执行,程序可以不用长时间停顿,比较适合于实时程序。其劣势是无法检测循环引用,计数器的加减带来额外开销。

2. 跟踪法:
        从根结点开始追踪对象引用图,遇到对象,打上标记,追踪结束时,没有标记的对象是无法触及的,则可以回收。可以在程序注册表、每一个线程堆栈中的局部变量以及静态变量中找到根。

        由于计数法的缺陷,这种技术已经不再应用到实际Java虚拟机中。下面主要介绍基于跟踪法的四种垃圾收集器:
1.跟踪收集器:
        分为标记和清除两个阶段。在标记阶段,停止程序,通过遍历引用图,标记可触及的对象。在清除阶段,清除未被标记的对象,释放它们的内存。
         跟踪收集器比较简单,同时可以收集循环引用,而且不会有计数器加减的额外代价。但是它的不足之处是,标记阶段可能使程序停顿的时间过长,清除阶段释放的内存容易产生内存碎片。

2.拷贝收集器:
        为了避免产生内存碎片,堆分成两个区域。一个区域空间耗尽,程序中止,堆被遍历,遇到活动对象拷贝到另一个区域连续地址空间上,内存从新的区域中分配,原来区域的内存被释放。
        这种技术虽然避免了释放对象时产生的内存碎片,但是任何时候只能使用堆的一半的存储空间。同时,对于对于生命周期比较长的对象,会频繁地在两个区域间来回拷贝,严重影响系统效率。

3.压缩收集器:
         在清除阶段,把活动对象移到堆的一端,堆的另一端出现一个大的连续空闲区。由于对象的位置被移动,对象的引用需要更新。
         通过对象句柄和对象句柄表,可以使对象引用变得更简单。对象引用不再直接指向堆中的对象,而是指向对象句柄表。对象句柄表中的对象句柄指向对象在堆中的实际位置。对象被移动后,只需要更新对象句柄,而不用修改对象引用。
        这种策略结合了跟踪收集器和拷贝收集器的优点,代价是收集阶段除了释放不可触及对象,还要移动活跃对象。这种策略的优势既解决了内存碎片,又使生命周期长的对象趋向于沉于堆的底部,从而避免了这些对象的频繁拷贝。

4. 按代收集器:
       虽然压缩收集器结合了跟踪收集器和拷贝收集器的优点,但是每次对象访问都要先经过对象句柄表,才能访问到堆中的对象。由于每次对象访问的额外一次访问,严重影响到程序性能,因此压缩收集器并不是完胜另外两种策略。
      按代收集器根据程序中对象生命周期的特点,将堆按代划分为子堆,每个子堆存储一代对象。越年轻的一代,收集的频率越高。一代中某对象经过几次垃圾收集仍然存活,就会被移到年龄更高的一代中。
      不同的代中,可以采用不同的收集器。年轻代中可以采用拷贝收集器,避免生命周期长的对象频繁来回拷贝的缺陷。年老代中可以采用跟踪收集器或者压缩收集器,避免了碎片整理带来的额外代价。

      Java的垃圾回收机制虽然相对于其他语言在内存管理上有很大优势,但是这种机制目前也存在一定的不足:
1. 降低程序性能:自动回收垃圾,需要暂停程序运行,占用CPU资源
2. 缺乏控制:垃圾回收由虚拟机实现,程序员无法控制
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值