对象回收:如果一个对象从“gc根集”开始,无法到达,那么这个对象就可以认为是被回收了。这里的根集在不同的垃圾收集器和不同区域的gc中表现不同。如果使用cmsgc,yanggc时,rootset包括:虚拟机栈中引用的对象:虚拟机栈中引用的对象可以作为GCRoot。我们的程序是在虚拟机的栈上执行的,每次函数调用都会压栈一次。栈包括局部变量表和操作数栈。局部变量表中的变量可能是引用类型,它们引用的对象可以作为GCRoot。但是,当函数调用结束并从堆栈中弹出时,这些引用就会消失。方法区中类的静态属性引用的对象:简单的说就是我们在类中使用的静态声明的引用类型字段方法区中的常量引用的对象:简单的说就是引用类型我们在类中final声明中使用的字段是local当方法栈中引用的对象在cmsgc中时,rootset包括:除了上面的,还包括年轻代的对象(不管是死的还是活的),包括在cmsgc期间提升的对象。四种强引用:我们一般在创建对象的时候都会用到强引用。只要存在强引用,对象就不会被gc回收,即使没有足够的空间抛出oom。软引用用于描述一些不重要但仍然有用的对象。当内存足够时,软引用对象不会被回收。只有当内存不足时,系统才会回收软引用对象。在系统即将发生内存溢出异常之前,这些对象会第二次被纳入回收范围。回收。如果本次回收内存不足,则会抛出内存溢出异常。.此功能通常用于实现缓存技术。弱引用的引用强度比软引用弱。不管内存是否充足,只要JVM启动垃圾回收,弱引用关联的对象就会被回收。它是用来帮助gc回收的。当对象存在强引用时,可以通过弱引用访问对象。当强引用不存在时,帮助gc回收。比如ThreadLocal的幻引用的实现就是最弱的一种引用关系。如果一个对象只持有一个虚引用,那么它就和没有引用一样。随时可能被回收,以PhantomReference类为代表,随时调用的get()方法都返回null,也就是说永远不会通过虚引用获取对象,并且虚拟引用必须与ReferenceQueue引用队列一起使用。当对象被回收时,虚拟引用将被添加到队列中。你可以通过判断引用队列是否已经加入来判断被引用的对象是否会被垃圾回收,这样你就可以在对象被回收之前采取一些必要的措施。.比如直接内存回收的执行。非强引用对象回收时机:如果一个对象只被非强引用指向,什么时候回收?软引用对象回收的时机:clock最后一次垃圾回收的时间戳,由垃圾回收器更新,全局共享timestamp最后一次获取软引用的时间,private。从这两个属性可以得到从上一次gc到软引用没有被访问的时间idletime(可能是负值)idletime=clock-timestamp同时我们有一个软引用的空闲保留时间(全局)idlelivetimeidlelivetime=堆中剩余内存(MB)*perMB空闲内存保留时间perMB空闲内存保留时间对应JVM参数-XX:SoftRefLRUPolicyMSPerMB。当需要回收软引用时,会回收空闲时间大于idlelivetime的软引用。当内存不足时,系统会回收软引用对象,在系统发生内存溢出异常之前,会将这些对象纳入回收范围进行第二次回收弱引用对象:只要JVM启动垃圾回收,那些与弱引用关联的对象将被回收。幻象引用对象回收的时机:幻象引用必须和队列一起使用。在jdk8之前及之前,在回收幻象引用对象时必须回收幻象引用对象。也就是说,当幻象引用对象被jdk回收时,必须对幻象引用进行处理,否则Space不会被释放。jdk9修改设计。特别说明:非强引用的处理由jvm后台线程异步处理。这些线程的优先级不高。也就是说,当gc活动结束时,这些对象可能不会立即被回收。如果频繁创建应用程序对象,可能会触发fullgc。完整的gc会stuw。当类被卸载时,该类的所有实例都已被回收加载该类的ClassLoder已被回收当达到metadataSize时,会触发oldgc,当容量扩展到maxMedataSize时,会触发fullgc.直接内存释放:直接内存的释放由继承虚引用的cleaner实现。当直接内存的强引用被回收时,jvm后台处理引用的线程会调用cleaner的clean方法,最后通过free释放空间。当直接内存的对象提升到老年代时,直到老gc发生,直接内存才会被释放,造成内存泄漏。
