垃圾回收基于“对象不再使用”的原则,自动检测并回收不再被引用的对象。JVM通过跟踪对象的引用关系来判断对象是否仍在使用中。当一个对象没有任何引用指向它时,垃圾回收器就会将其标记为可回收对象。
垃圾回收的工作机制
标记-清除(Mark-Sweep)算法:这是最基本的垃圾回收算法,分为两个阶段,首先标记出所有存活的对象,然后清除所有未被标记的对象。但这种算法可能会导致内存碎片化。
复制(Copying)算法:将内存分为两个相等的区域,当一块区域被填满时,垃圾回收器将存活的对象复制到另一块区域,然后清除原区域的所有对象。这种算法可以避免内存碎片化,但会浪费一半的内存空间。
标记-压缩(Mark-Compact)算法:结合了标记-清除和复制算法的优点,标记存活对象,然后将所有存活对象压缩到一块连续的内存区域,并直接清除边界以外的内存。这样可以避免内存碎片化,同时节省了内存空间。
分代收集(Generational)算法:根据对象的存活周期将内存分为新生代和老生代。新生代通常采用复制算法,频繁地回收新生代;老生代则采用标记-清除或标记-压缩算法,较少地进行垃圾回收。这种算法可以显著提高垃圾回收的效率。
垃圾回收的优化实践
1.调整堆内存大小:根据应用的特点和需求,合理设置堆内存的大小,可以避免频繁的垃圾回收和OutOfMemoryError异常。
2.对象引用优化:尽量避免全局变量和静态变量持有对象引用,以减少被标记为存活的对象数量。
3.并发编程与垃圾回收:在多线程环境下,合理使用并发工具类(如java.util.concurrent包中的类),以减少线程间的对象共享,降低垃圾回收的负担。
4.避免大对象和长期存活的对象:大对象和长期存活的对象会占用大量的堆内存,增加垃圾回收的负担。尽可能地减小对象的大小或者缩短对象的存活周期。
5.监控与调优:使用JVM提供的监控工具(如jconsole、jvisualvm等)监控垃圾回收的状态和性能指标,根据实际情况进行调优。
JVM的内存区域和常见GC
内存主要被分为三块:新生代(Youn Generation)、旧生代(Old Generation)、持久代.
常见的GC算法:复制、标记-清除和标记-压缩
引用计数法 (java没有采用)
- 引用计数算法(Reference Counting)比较简单,对每个对象保存一个整型 的引用计数器属性。用于记录对象被引用的情况。
- 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。
可达性分析算法
- 可达性分析算法是以根对象集合(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。
- ➢使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链(Reference Chain)
- ➢如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。
- ➢在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。