【Java】Java GC机制

  Java有垃圾回收器负责回收无用对象占据的内存资源。但是也有例外情况,由于垃圾回收器只知道释放那些经由new分配的内存,如果你的对象不是使用new获得了一块“特殊”的内存区域,那么它就不知道该如何处理对象的这块“特殊”内存。

  finalize() 方法: 为了应对上述情况,Java 允许在类中定义一个名为 finalize() 的方法,它的工作原理”假定“ 是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其 finalize() 方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。

1:对象可能不被垃圾回收

     只要 JVM 并未面临内存耗尽的情况,它是不会浪费时间去执行垃圾回收以恢复内存。也就是说,只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。如果程序执行结束,并且垃圾回收器一直都没有释放你创建的任何对象的存储空间,则随着程序的退出,那些资源会被全部交还给操作系统。

2:垃圾回收并不等于析构

    Java并未提供”析构函数“或类似概念,要做类似的清理工作,必须自己动手创建一个执行清理工作的普通方法。

3:垃圾回收只与内存有关

    使用垃圾回收器的原因就是回收程序不再使用的内存。所以对于垃圾回收有关的任何行为来说,尤其是 finalize() 方法,它们必须同内存或回收有关。

   无论对象如何创建,垃圾回收器都会负责释放对象占据的所有内存。那么 finalize() 方法就会被限制到一种特殊的情况,那就是通过某种创建对象以外的方式为对象分配了存储空间。在非 Java的代码中,如果调用了 C 的 malloc() 函数系列来分配存储空间,而且除非调用了 free() 函数,否则存储空间将不会被释放,从而造成内存泄漏。

4:引用计数

  引用计数是一种简单但是速度很慢的垃圾回收技术。每个对象都有一个引用计数器。当引用和对象连接时,引用计数器加1,当引用离开作用域或被置 null 时,计数器减1。垃圾回收器会在含有全部对象的列表上遍历,当发现某个对象的引用计数为0时,就会释放器占用空间,但是,引用计数模式经常会在计数值变为0时,立即释放对象。这种方法存在缺陷,如果对象之间存在循环引用,可能会出现”对象应该被回收,但引用计数却不为零“的情况。引用计数常用来说明垃圾收集的工作方式,但似乎从未被应用于任何一种JVM实现中。

  垃圾回收器并非基于引用计数技术,它依据的思想:对与任何活的对象,一定能追溯到其存活在堆栈或静态存储区之中的引用。这个引用链条可能会穿过无数个对象层次。由此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到活的对象。对于发现的每个引用,追踪它所引用的对象,然后是对象所包含的引用,如此反复,直到堆栈和静态存储区的引用所形成的网络被全被访问为止。由于所访问的对象都必须是活的,所以这就解决了”交互自引用的对象“问题。

5:自适应技术

  自适应技术等同于“自适应的,分代的,停止—复制,标记—清扫”式垃圾回收器。

  停止—复制(stop-and-copy):先暂停程序的运行(但事实上JVM并非以这种方式实现,当可用内存数量较低时,垃圾回收器才会暂停程序),然后将所有存活的对象从当前堆复制到另一个堆,没有被复制的全部都是垃圾,不属于后台回收模式。当把对象从一个地方搬到另一个地方,所有指向它的引用都必须被修正。位于堆和静态存储区的引用可以直接被修正,但可能还有其他指向这些对象的引用,他们在遍历过程才能被找到。这种复制式回收器效率会降低,首先需要两个堆,然后在这两个堆上进行操作,所以维护了比实际多一倍的空间。有的JVM,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之间。

  标记—清扫(mark-and-sweep):程序进入稳定状态后,可能只会产生少量的垃圾,甚至没有垃圾,复制回收器仍然会将内存从一处复制到另一处,为了避免这种情况,JVM会进行检查:要是没有新垃圾产生,就会转到标记—清扫模式。标记—清扫所依据的思路和停止—复制同样是从堆栈和静态存储区出发,遍历所有的引用,从而找出所有存活的对象,每当它找到一个对象就会设一个标记,这个过程不会回收对象。只有全部标记工作完成时,清理动作才会开始,没有被标记的对象就会被释放,不会发生任何复制动作。当可用内存数量较低时,标记—清扫也必须在程序暂停的情况下才能进行。

  分代的:这里所述的JVM,内存分配试一较大的”块“为单位。停止—复制要求在释放旧有对象之前,必须先把所有存活对象从旧堆复制到新堆,这将导致大量的内存复制行为。有了块之后,垃圾回收器在回收的时候就可以往废弃的堆里拷贝对象。每个块都有一个代数来记录它是否还存活。如果块在某处被引用,其代数会增加。垃圾回收器会对上次回收动作之后新分配的块进行整理。这对处理大量短命的临时对象很有帮助。垃圾回收器会定期进行完整的清理动作,大型对象不会被复制,其代数会增加,内含小型对象的那些块则被复制并整理。

  自适应的:JVM会进行监视,如果所有对象都很稳定,垃圾回收器的效率降低的话,就会切换到标记—清扫模式,同样JVM会监视标记—清扫的效果,要是堆空间出现很多碎片,就会切换回停止—复制模式。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值