Java中的引用类型和OOM

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38120325/article/details/81282769

Java的四种引用类型与OOM

         在项目中遇到了一个打开页面初始化数据的问题,之前没有考虑到初始化的Map中数据量大会影响内存,因为初始化的Map是在进行其他操作之后才会销毁,后来经过考虑使用Redis进行存取,用用户的sessionID作为key去存储Map;根本没想到使用引用类型,后来看到引用类型,想起了之前遇到的问题,记录一下,还有内存优化,避免OOM的问题;

  • Java的四种引用类型

在java中虽然不需要手动去管理对象的生命周期,但是在变成过程中,必须注意要释放无用资源,节省内存空间,遇到不能释放的对象,就需要通过利用java的弱引用和软引用来避免OOM;

Java SE2以后,就提供了四种类型的引用;强引用、软引用、弱引用和虚引用。主要目的是为了让程序员控制对象的生命周期和让JVM进行垃圾回收:

  1. 强引用:

代码中普遍存在的

只要某个对象有强引用与之关联,JVM必定不会回收这个对象,最后的结果是OOM;在程序中一般使用对象赋值为null的释放内存,在Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的

  1. 软引用

软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。

           软引用结合引用队列来使用,相当于二级缓存,当内存不够用时,清空!

ReferenceQueue,pollremove方法;

 

  1. 弱引用

        弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。比如Map中的WeakHashMap,属于弱引用对象!

  1. 虚引用

虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在Java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可以被垃圾回收器回收。要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

A、当我们在高速缓存中缓存较大的对象例如缓存图片等以提高读取速度的时候(针对大内存对象问题),可以将相关的对象设置为软引用对象,这样保证在内存不够用的时候GC可以进行回收工作。

B、当我们完全不像由于当前对对象的引用而影响对象的其他模块原来设定的GC回收时期,我们可以采用弱引用(相当于只可访问数据而访问不会对GC对对象的回收造成影响)

C、当然,java还有一种叫做虚引用的引用类型变量,该变量其实现实中用得不多,主要用来跟踪对象GC过程,所以这里不详细讲。

 二、Java中的OOM

         OOM就是说,当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个Error(注:非Exception,因为这个问题已经严重到不足以被应用处理,当然Exception也分运行时异常和Checked异常,前者编译可通过,运行是抛出异常,后者编译时必须try-catch到,如IO操纵等和运行环境有关而与程序本身无关的异常)。

         原因:初始化分配内存过少,应用申请太多或者使用完成没有释放;

                  内存泄露:申请使用完的内存没有释放,导致虚拟机不可以使用该内存;

                  内存溢出:申请的内存超过了JVM提供的大小!

         常见类型:

  1. Java堆内存溢出:
  2. 虚拟机栈和本地方法栈
  3. 运行时常量池溢出
  4. 方法区溢出

     按照JVM规范,Java虚拟机在运行时会原理一下的内存区域:

           程序计数器:当前线程执行的字节码的信号指示器,线程私有

           Java虚拟机栈:Java方法执行的内存模型,每个方法的执行对应着一个栈帧的压栈和弹栈操作!

           本地方法栈:类似Java虚拟机栈,但是为native方法的运行提供内存环境

           Java:对象内存分配的地方,内存垃圾回收的主要区域,所有线程共享,可以分为新生代和老生代等

           方法区:用于存储已经被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Hostpot中的永久代

           运行时常量池:方法区的一部分,存储常量信息,在方法运行时产生的常量信息;

           直接内存:并不是JVM运行时的数据区的一部分,可直接访问的内存,比如NIO会用到这部分。

 

猜你喜欢

转载自blog.csdn.net/m0_38120325/article/details/81282769