1. 垃圾回收机制
1.1. 自动垃圾回收
Java编程语言的一个特色就是其自动垃圾回收机制,不像C/C++那样,内存的分配和释放都是程序员手动操作的。
有人认为,碎片化(not GC)是影响java程序性能的主要原因。当前主流(并不一定是最新的)的处理堆内存碎片化问题的解决方式是分代GC&紧致(Generational GC & compaction)。
1.2. GC的运行原则和机制
Garbage Collector垃圾回收器,是在后台运行的程序,它照看所有内存中的对象,找到没被程序中任何其他部分所引用的对象。所有这些未被引用的对象被删除,其空间被释放用来分配给其他对象。
当我们命令行运行一个程序时,如果设置命令行参数java -Xmx:2g MyApp , 则表示分配了2g的内存给该java进程,即heap内存。在程序运行时,总有堆内存耗尽的时刻,这时新的线程因为没有连续内存空间而无法被创建。这个时候JVM决定开始进行garbage collection,当然我们也可以显式地调用Sys tem.gc()来建议JVM进行垃圾回收 (之所以说是建议,因为JVM并不一定保证会进行垃圾回收)。
GC的进行需要有2个条件满足:1). 绝不回收当前依然存活的对象--有活跃引用的对象。2). 成为垃圾的对象dead objects也不是保证被立即回收的。这取决于回收策略:是保证足够的内存使用还是保证系统整体的延迟和吞吐量的考量。
1.3. 2类垃圾回收方案:
a). Referencing Counting collectors: 引用计数垃圾回收器
思想:记录下指向每一个对象的引用数量,一旦一个对象的引用数为0则将其回收。
优点:可以立即对称为垃圾的对象进行回收,速度快;且算法简单。
缺点:其一,当对象过多时,开销大;其二,主要原因--无法解决循环引用对象问题Circular referencing.\
b). Tracing collectors: 跟踪回收器
思想:所有活的 live对象可以在当前已知的活的对象(root object 存在于 registers, global fields, stack frames)中找到其引用。
优点:解决了循环结构问题(本文之后所有内容都是针对于Tracing collectors而言的)。
缺点:对大部分跟踪收集器而言,在标记阶段--在回收未被引用的垃圾对象时需要等待。
1.4. 2大类Tracing Collector
1.4.1 复制回收器Coping Collectors
![](https://i-blog.csdnimg.cn/blog_migrate/7e093d41596ff8fc5a8a1d552d915b87.png)
原理:在堆上有2块单独定义的地址from-space & to-space, 在垃圾回收时,from-space的存活的对象被复制到to-space中,然后from-space中进行垃圾回收。
优点:在 to-space中对象在内存中很紧致地放在一起, 完全没有了内存碎片化的烦恼。
缺点: 复制回收器是一种 stop-the-world collector, 意味着在垃圾回收循环中,其他应用不能执行,这对于需要高响应速度的应用而言无法容忍;而且,当from-space中的所有对象都不是垃圾--都是live对象时,to-space需要有很大空间存放from-space内容,这也使得其效率很差。
1.4.2 标记-清理回收器Mark-and-sweep collector
大部分商业JVM是使用mark-and-sweep 垃圾收集器的, 因为它没有copy-collector的负面性能缺点。一些最著名的回收策略包括:CMS, G1, GenPar(
link)都是采用mark-and-sweep策略的!
原理:mark-and-sweep 垃圾回收器跟踪并标记每个live对象用一个'live'标志位。在所有的live对象都已被mark之后,进行的将是sweep操作;sweep将遍历整个heap空间,找到未被标记的内存空间地址,收集器将这些未被标记的内存空间地址链接在一起并组织成自由的表free-l