如何在网上接做网站的小项目seo整站优化外包公司
目录
- 1. 如何判断对象可以回收
- 1-1. 引用计数法
- 1-2. 可达性分析算法
- 1-3. 四种引用
- 强引用
- 软引用
- 弱引用
- 虚引用
- 终结器引用
- 2. 垃圾回收算法
- 2-1. 标记清除
- 2-2. 标记整理
- 2-3. 复制
- 2-4. 总结
- 3. 分代垃圾回收
- 4. 垃圾回收器
- 5. 垃圾回收调优
1. 如何判断对象可以回收
1-1. 引用计数法
引用计数法
- 只要一个对象被其他变量所引用,那么就让这个对象的计数
+1
- 如果其他变量不再引用,让这个对象的计数
-1
- 让这个对象的引用计数为
0
时,则说明没有变量引用了,就可以作为一个垃圾进行回收
引用计数法弊端
- 循环引用问题,A对象与B对象循环引用,他们的引用计数始终为1,不能作为一个垃圾进行回收
- 出现内存泄漏
1-2. 可达性分析算法
根对象:一些肯定不能作为垃圾的对象
可达性分析算法
-
在垃圾回收之前,会对堆内存所有的对象进行扫描
-
查看每一个对象是不是被
根对象直接或间接引用
-
如果是,则不能被垃圾回收
-
如果不是,则可以被垃圾回收
-
Java虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
-
扫描堆中的对象,看是否能够沿着GC Root对象
(堆中对象)
为起点的引用链找到该对象,找不到,表示堆中对象
可以回收 -
哪些对象可以作为GC Root
- 活动线程中局部变量
所引用的堆中对象
可以作为根对象
- 活动线程中局部变量
1-3. 四种引用
实线代表强引用
平时用的引用都是强引用
,例如:赋值运算
强引用
- 所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收。
软引用
- 只有【软引用】引用该对象时,在垃圾回收后,内存仍不足 则会回收软引用对象
- 可以配合【引用队列】来释放软引用自身,因为软引用自身也占用内存
★应用场景
- 非核心业务资源(比如:图片)被强引用特别多时,有可能报OOM异常,因为强引用是不会被回收的,内存满直接抛异常
- 那么就可以用【软引用】来指向这些资源,当内存不足时,回收这些资源。
- 以后如果再使用图片资源,重新读取一遍。
弱引用
- 只有【弱引用】引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
- 可以配合【引用队列】来释放弱引用自身,因为弱引用自身也占用内存
虚引用
- 必须配合【引用队列】使用
- 例如
ByteBuffer
对象不再【强引用】时,ByteBuffer
对象本身可以被垃圾回收,但是占用的直接内存
是属于操作系统的,无法被回收。 - 那么就可以将【虚引用】放入【引用队列】, 由
Reference Handler
线程调用虚引用相关方法释放【直接内存】 - 总结:【虚引用】引用的对象被垃圾回收时,【虚引用】被放入【引用队列】,从而由一个线程可以调用【虚引用】的方法。
终结器引用
Object
类中有finallize()
方法- 当一个类重写了
Object
类中有finallize()
方法,并且该对象没有被【强引用】时,就可以进行垃圾回收 - 第一次垃圾回收时,将【终结器引用】放入【引用队列】,并且由一个优先级很低的Finalizer线程去寻找【终结器引用】的对象,找到后执行该对象的
finallize()
方法。 - 直到第二次垃圾回收时,才将该对象进行垃圾回收。
软引用使用:
public class Demo1 {public static void main(String[] args) {final int _4M = 4*1024*1024;//list是强引用,byte数组是软引用List<SoftReference<byte[]>> list = new ArrayList<>();SoftReference<byte[]> ref= new SoftReference<>(new byte[_4M]);}
}
软引用配合引用队列使用:
public static void main(String[] args) throws IOException {///使用引用队列,用于移除引用为空的软引用ReferenceQueue<byte[]> queue=new ReferenceQueue<>();List<SoftReference<byte[]>> list = new ArrayList<>();for (int i = 0; i < 5; i++) {//关联了引用队列,当软引用所关联的byte数组被回收时,软引用自己就会加入到引用队列queue中去SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB],queue);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}//获取队列中第一个软引用Reference<? extends byte[]> poll = queue.poll();//遍历引用队列,如果有软引用,则移除while(poll!=null){list.remove(poll);poll=queue.poll();}System.out.println("=============");System.out.println("循环结束:" + list.size());for (SoftReference<byte[]> ref : list) {System.out.println(ref.get());}
}
弱引用使用:
弱引用的使用和软引用类似,只是将 SoftReference
换为了 WeakReference
public static void main(String[] args) {//list是强引用,byte数组是弱引用List<WeakReference<byte[]>> list=new ArrayList<>();for (int i = 0; i < 5; i++) {WeakReference<byte[]> ref=new WeakReference<>(new byte[_4MB]);list.add(ref);for (WeakReference<byte[]> w : list) {System.out.print(w.get()+" ");}System.out.println();}System.out.println("循环结束:"+list.size());
}
2. 垃圾回收算法
2-1. 标记清除
标记清除
在垃圾回收的过程中
- 标记:确定哪些对象是可回收对象,
- 清除:标记好之后,清除可回收对象的内存,
并不是将内存空间字节清零
,而是记录内存起始地址。
注意:这里的清除并不是将内存空间字节清零,而是记录这段内存的起始地址,下次分配内存的时候,会直接覆盖这段内存。
优点: 速度快
缺点: 容易产生内存碎片。一旦分配较大内存的对象,由于内存不连续,导致无法分配,最后就会造成内存溢出问题
2-2. 标记整理
标记整理
- 先采用标记算法确定可回收对象
- 然后整理剩余的对象内存,将可用的对象内存移动到一起,使内存更加紧凑,连续的空间就更多。
优点:不会有内存碎片
缺点:速度慢
2-3. 复制
复制算法
- 将内存分为等大小的两个区域,FROM和TO(TO中为空)。
- 将被GC Root引用的对象从FROM放入TO中,然后回收不被GC Root引用的对象。
- 回收完之后交换FROM和TO两个区域。这样也可以避免内存碎片的问题,但是会占用双倍的内存空间。
优点:不会有内存碎片
缺点:会占用双倍的内存空间。速度慢
2-4. 总结
- JVM会根据不同的情况来采用这3种算法
- 不会只使用一种算法