一.什么是OOM
- OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError
- OOM是一种Error,不是Exception,是程序的错误而并非异常
- 当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error
内存泄漏和内存溢出
这两个也是经常提到的术语:
- 内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用
- 内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出
二.强引用Reference
当内存不足,JVM开始垃圾回收,对于强引用对象,就算出现了OOM也不会堆该对象进行回收。
强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表面对象还“或者”,垃圾收集器不会碰这种对象。在Java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,他是不可能被垃圾回收机制回收的,既是该对象以后永远都不会被用到 JVM也不会回收。因此强引用时造成java内存泄漏的主要原因之一。
代码实例
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = obj1;//强引用
obj1 = null;
System.gc();//进行gc
System.out.println(obj2);
}
结果发现obj2并没有被回收,可以打印出其内存地址。
三.软引用
- 软引用是一种相对强引用弱化了一些作用,需要用
java.lang.ref.SOftReference
类来实现,可以让对象豁免一些垃圾收集。 - 当系统内存充足时他不会被回收,当内存不足时会被回收。
- 软引用通常在对内存敏感的程序中,比如高速缓存就有用到软引用,内存足够的时候就保留,不够就回收。
软引用跟强引用不一样,软引用需要借助SoftReference类
Object obj1 = new Object();
SoftReference<Object> ref = new SoftReference<>(obj1);
//获得其引用对象
ref.get();
四.弱引用 WeakReference
- 弱引用需要用java.lang.ref.WeakReference类来实现,比软引用的生存期更短
- 只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收。
Object obj1 = new Object();
WeakReference<Object> ref = new WeakReference<>(obj1);
System.out.println(ref.get());
System.gc();
System.out.println(ref.get()); //gc后 该引用被回收
五.虚引用PhantomReference
- 虚引用并不会决定对象的生命周期
- 如果一个对象持有虚引用,那么他就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,他不能单独使用也不能通过它访问对象,虚引用和引用队列(ReferenceQueeu)联合使用
- 虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保ui想被finalize以后,做某些事情的机制
- 设置虚引用关联的唯一目的,就是这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理
引用队列
创建引用的时候可以指定关联的队列,当gc释放对象内存的时候,会把引用加入到引用队列,如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动,相当于通知机制
当关联的引用队列中有数据的时候,意味着引用指向的对内存中的对象被回收。通过这种方式,jvm允许我们在对象被小回收,做一些我们自己想做的事情。