Java的垃圾回收机制

垃圾回收机制(GC)。在以前所用过的程序语言中,在堆上分配对象的代价十分高昂,因此会认为Java中所有对象(基本类型除外)都在堆上分配的方式也十分高昂。然而,垃圾回收器对于提高对象的创建速度,却有明显的效果。听起来很奇怪–存储空间的释放竟然影响存储空间的分配,但这确实是某些Java虚拟机的工作方式。这也意味着,Java从堆分配空间的速度,可以和其他语言从堆栈上分配空间的速度相媲美。–from Thinking in Java(Java编程思想)

什么是垃圾回收机制?

  • Java的垃圾回收机制是Java虚拟机提供的,一般是在空闲时间以不定时的方式动态回收无任何引用的对象占据的空间。
  • 回收的是无任何引用的对象占据的内存空间而不是对象本身
  • 具体的垃圾回收操作是不可预料的,不能人为的干预。
  • gc()可以建议虚拟机进行垃圾回收,但是虚拟机不一定接受你的建议

垃圾回收策略

  • 引用计数收集器
    • 引用计数是垃圾回收器的早期策略,对于堆中的对象都有一个引用计数。当一个对象被创建时,该对象会被分配给一个初始值为1的变量,当任何其他的变量被赋值为该对象的引用时,引用计数+1,当一个对象的某个引用超过了声明周期或被设置为一个新值时,对象的引用计数-1。当引用计数为0时,垃圾回收器会在适当的时候进行垃圾回收。
    • 缺点:当父对象和子对象互相引用时,就会造成循环引用。
    • 优点:引用计数器可以很快的执行,对程序不被长时间打断的实时环境比较有利。
  • 跟踪收集器
    • 现在大多数的JVM采用对象引用遍历,对象引用从一组对象开始,沿着整个对象图上的链接,确定可以递归到达的对象,如果某个对象不能从这些根对象的至少一个到达(即没有被任何对象引用),则会被当作垃圾进行回收。
    • GC删除对象时,有些GC只是简单的扫描堆栈,删除未标记的对象,并释放他们的内存以生成新的对象,这叫做清除。不过这样会把内存分为好多小段,这些内存段虽然不足以存储新的对象,但是组合起来却很大。因此,许多的GC可以重新组织内存中的对象,并进行压缩,形成可以利用的空间。

    常用的垃圾回收算法

    垃圾回收算法无外乎是时间和空间的置换,如何选择具体的垃圾回收算法,应该取决于一个“中庸之道”,当然,Java的垃圾回收机制也不一定是最完美的。随着Java虚拟机的发展,垃圾回收机制也在不断的进行适应和完善。况且,不同的JVM采用的垃圾回收算法也有可能是不同的。

  • Mark-Sweep(标记-清除)算法

    最容易实现和理解的一种算法。垃圾的回收主要分为两个阶段:标记阶段和清除阶段。

    • 标记阶段的任务就是标记出所有的被回收的对象。
    • 清除阶段就是回收被标记的对象所占的内存空间。
  • Copying(复制)算法

  • Mark-Compact(标记-整理)算法

  • Generational Collection(分代收集)算法

什么是内存泄漏?

内存泄漏简单来说就是内存使用完毕后未回收。

参考

上篇Java 中的 enum
下篇Java 中的 单例