垃圾收集机制
- 需要被收集的垃圾: 1.没有引用指向的对象。2.两个对象互相引用,且没有外部引用指向他们。3. 多个对象环形引用,形成一个闭环,且没有外部引用指向他们。
- 回收规则: 正向可达 算法。从roots对象计算可以到达的对象都不是垃圾。root对象举例:main方法中的创建的所有对象;java虚拟机启动时的ClassLoader。
-
垃圾收集算法:
- Mark-Sweep 标记算法:没有被引用的对象一一标记出来,GC运行时进行清除。缺点:清除后内存不连续、碎片化。 空和不空的内存块互相间隔着,若有一个比较大的对象进入时,有可能找不到可以存下它的连续整块内存。这时会触发fullGC,全部回收,压缩,再存下新对象。影响效率。
- Copying 复制算法:内存被平成两个连续的区域。永远有一个内存区是空着的,回收被使用的一块内存时,直接把存活对象全部拷贝到空着的一块内存区中,并清空本内存区。内存复制的效率很高,并保证了内存块的连续性。缺点:内存浪费,永远只能用一半。
java堆内存的 新生代 中垃圾收集时用的是复制算法。新生代分成了三块内存区:Eden、 Survivor0、Survivor1。GC运行时按正向可达规则将Eden中存活对象复制到S0内存块中,并清除当前内存块,下一次GC时,将S0和Eden中存活的对象复制到S1中,清除Eden和S0,如此往复。内存大小比例为8:1 : 1。 因为对象创建时最初存放于eden 而90%以上的对象往往在方法结束后被回收,留下的很少,故S0和S1比例可远小于Eden。 ps:堆内存的性能优化方式可参考:
- Mark-Compact 标记压缩 被标记的对象回收后,把存活对象压缩到一起,留下连续的内存块。缺点:效率低于copy算法
java堆内存的 老年代 中垃圾收集时一般用的是标记压缩法。老年代中新产生的垃圾较少,但是堆积的垃圾可能很多,故标记压缩的在该内存块下效率不会太低,也保证了内存空间不浪费。
-
引用的类型: 强引用;软引用;弱引用;虚引用。
- 经常使用的
String a = new String("abc")
都为强引用,即使内存不够时,只要引用存在,都不会被清除,此时就报OutOfMemory。 - 软引用
SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>();
该引用在内存不够的情况下会被强制清除。如在读取大量图片的应用场景中,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出。此时就可以使用软引用的方式来存取图片。 - 弱引用。只要发生垃圾回收,都会被清除
- 经常使用的
END