jvm对象回收

【jvm对象回收】对象回收:
如果一个对象从”gc root set“出发,无法到达,那么这个对象即可以被认为可以被回收。这里root set在不同垃圾回收器、不同区域的gc表现不同。如使用cms gc,
在yang gc的时候,root set包含:
虚拟机栈中引用的对象:虚拟机栈中的引用的对象可以作为GC Root。我们程序在虚拟机的栈中执行,每次函数调用调用都是一次入栈。在栈中包括局部变量表和操作数栈,局部变量表中的变量可能为引用类型(reference),他们引用的对象即可作为GC Root。不过随着函数调用结束出栈,这些引用便会消失。
方法区中类静态属性引用的对象:简单的说就是我们在类中使用的static声明的引用类型字段
方法区中常量引用的对象:简单的说就是我们在类中使用final声明的引用类型字段
本地方法栈中引用的对象
在cms gc的时候,root set包含:除了以上的,还包括年轻代的对象(无论死活)、包括cms gc期间晋升的对象。
四种引用
强引用:我们一般创建对象的时候使用的都是强引用,强引用只要存在,对象就不会被gc回收,哪怕空间不够抛出oom。
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。。这种特性常常被用来实现缓存技术。
弱引用的引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。用来帮助gc回收,当对象的强引用存在时,可以通过弱引用访问这个对象,当强引用不存在时,帮助gc回收。比如ThreadLocal的实现
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,用 PhantomReference 类来表示,任何时候调用它的 get() 方法都是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。在对象被回收时,会将虚引用加入队列,可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。如直接内存回收的实现。
非强引用对象回收时机:如果一个对象只有非强引用指向,什么时候回收?
软引用对象回收的时机:
clock 上次发生垃圾回收的时间戳,由垃圾回收器更新,全局共享
timestamp 该软引用最后一次被获取的时间, 私有.
从这两个属性可得从上次gc起某个软引用未被访问的时间 idletime(可能为负值)
idletime = clock - timestamp
同时我们有软引用空闲保留时间(全局) idlelivetime
idlelivetime = 堆中剩余内存 (MB)* 每MB空闲内存保留时间
每MB空闲内存保留时间对应JVM参数 -XX:SoftRefLRUPolicyMSPerMB
当需要对软引用进行回收时,idletime大于 idlelivetime的软引用会被回收.
在内存不足时,系统则会回收软引用对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收
弱引用对象回收的时机:
只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。
虚引用对象回收的时机:
虚引用必须配合队列使用,在jdk8及以前,虚引用对象要被回收必须将虚引用本身回收掉,也就是说虚引用对象被jdk回收时,必须处理虚引用,不然空间不会释放。jdk9修改设计。
特殊说明:非强引用的处理都是jvm后台线程异步处理的,这些线程优先级并不高,也就是说gc活动结束时,这些对象并不一定立马回收了,如果应用程序对象创建频繁,可能触发fullgc。full gc会stw。
类卸载的时机

  1. 该类所有的实例已经被回收
  2. 加载该类的ClassLoder已经被回收
  3. 该类对应的java.lang.Class对象没有任何对方被引用
    元空间的gc:
当元空间不够的时候扩容,当扩容到metadataSize的时候会触发一次old gc,当扩容到maxMedataSize的时候,会触发一次full gc。
直接内存释放:
直接内存的释放是由cleaner实现的,cleaner继承虚引用,当直接内存的强引用回收掉时,jvm后台处理引用的线程就会调用cleaner的clean方法,最终通过free释放空间。当直接内存的对象晋升到了老年代,那么在发生old gc之前,这一块直接内存都不会释放,造成内存泄漏。

    推荐阅读