1、可达性分析(根搜索)算法html
JVM经过可达性分析来断定对象是否存活。这个算法的基本思路就是经过一系列称为GC Roots
的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots
没有任何引用链相连时,则证实此对象是不可用的。以下图中对象object1
、object2
、object3
、object4
是可用的对象,object5
、object6
、object7
虽然互相关联,可是它们到GC Roots
是不可达的,因此它们将会被断定为是可回收的对象。java
在Java语言中,可做为GC Roots的对象包括下面几种:算法
一、虚拟机栈(栈帧中的本地变量)中引用的对象。spring
二、方法区中类静态属性引用的对象。设计模式
三、方法区中常量引用的对象。安全
四、本地方法栈中JNI(Native方法)引用的对象。jvm
2、spring源代码学习
spring
建立对象是经过实现接口BeanFactory
的类来实现的,有以下的实现结构:测试
SimpleJndiBeanFactory.javathis
public class SimpleJndiBeanFactory extends JndiLocatorSupport implements BeanFactory { private final Set<String> shareableResources = new HashSet(); //使用new建立的map,是栈中引用的对象,可做为GC Roots 对象 private final Map<String, Object> singletonObjects = new HashMap(); private final Map<String, Class<?>> resourceTypes = new HashMap(); public SimpleJndiBeanFactory() { this.setResourceRef(true); } public void addShareableResource(String shareableResource) { this.shareableResources.add(shareableResource); } public void setShareableResources(String... shareableResources) { this.shareableResources.addAll(Arrays.asList(shareableResources)); } public Object getBean(String name) throws BeansException { return this.getBean(name, Object.class); } }
StaticListableBeanFactory.java
public class StaticListableBeanFactory implements ListableBeanFactory { private final Map<String, Object> beans; public StaticListableBeanFactory() { //使用new建立的map,是栈中引用的对象,可做为GC Roots 对象 this.beans = new LinkedHashMap(); } public StaticListableBeanFactory(Map<String, Object> beans) { Assert.notNull(beans, "Beans Map must not be null"); this.beans = beans; } public void addBean(String name, Object bean) { this.beans.put(name, bean); } }
从上面的源代码能够看出,对象存放在一个Map中,其中mapsingletonObjects
是用来存放单例对象的。map singletonObjects
和beans
(在构造方法中new)都是直接使用关键字new
建立,是强引用,知足做为GC Roots
对象的条件(虚拟机栈(栈帧中的本地变量)中引用的对象)。这样建立的对象存在map
中和GC Roots对
象相连,因此不会被回收。
总结
以上就是这篇文章的所有内容了,但愿本文的内容对你们的学习或者工做能带来必定的帮助,若是有疑问你们能够留言交流。
以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索spring , 垃圾回收 , 建立 类回收 spring 垃圾回收、java 对象垃圾回收、lua 全局对象垃圾回收、杉德卡保证金回收网点、资本回收保证量,以便于您获取更多的相关知识。
首先说一下为何会产生这一疑问,笔者本人再此以前历来没有考虑过垃圾回收对单例模式的影响,直到去年读了一本书,《设计模式之禅》秦小波著。在书中提到在j2ee应用中,jvm垃圾回收机制会把长久不用的单例类对象看成垃圾,并在cpu空闲的时候对其进行回收。以前读过的几本设计模式的书,包括《java与模式》,书中都没有提到jvm垃圾回收机制对单例的影响。而且在工做过程当中,也没有过单例对象被回收的经历,加上工做中不少前辈曾经告诫过笔者:尽可能不要声明太多的静态属性,由于这些静态属性被加载后不会被释放。所以对jvm垃圾收集会回收单例对象这一说法持怀疑态度。渐渐地,发如今同事中和网上的技术人员中,对这一问题也基本上是鲜明的对立两派。那么到底jvm会不会回收长久不用的单例对象呢。
对这一问题,笔者本人的观点是:不会回收。
下面给出本人的测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
本段程序的目的是模拟j2ee容器,首先实例化单例类,这个单例类占6M内存,而后程序进入死循环,不断的建立对象,逼迫jvm进行垃圾回收,而后观察垃圾收集信息,若是进行垃圾收集后,内存仍然大于6M,则说明垃圾回收不会回收单例对象。
运行本程序使用的虚拟机是hotspot虚拟机,也就是咱们使用的最多的java官方提供的虚拟机,俗称jdk,版本是jdk1.6.0_12
运行时vm arguments参数为:-verbose:gc -Xms20M -Xmx20M,意思是每次jvm进行垃圾回收时显示内存信息,jvm的内存设为固定20M。
运行结果:
……
[Full GC 18566K->6278K(20352K), 0.0101066 secs]
[GC 18567K->18566K(20352K), 0.0001978 secs]
[Full GC 18566K->6278K(20352K), 0.0088229 secs]
……
从运行结果中能够看到总有6M空间没有被收集。所以,笔者认为,至少在hotspot虚拟机中,垃圾回收是不会回收单例对象的。
后来查阅了一些相关的资料,hotspot虚拟机的垃圾收集算法使用根搜索算法。这个算法的基本思路是:对任何“活”的对象,必定能最终追溯到其存活在堆栈或静态存储区之中的引用。经过一系列名为根(GC Roots)的引用做为起点,从这些根开始搜索,通过一系列的路径,若是能够到达java堆中的对象,那么这个对象就是“活”的,是不可回收的。能够做为根的对象有:
方法区是jvm的一块内存区域,用来存放类相关的信息。很明显,java中单例模式建立的对象被本身类中的静态属性所引用,符合第二条,所以,单例对象不会被jvm垃圾收集。
虽然jvm堆中的单例对象不会被垃圾收集,可是单例类自己若是长时间不用会不会被收集呢?由于jvm对方法区也是有垃圾收集机制的。若是单例类被收集,那么堆中的对象就会失去到根的路径,必然会被垃圾收集掉。对此,笔者查阅了hotspot虚拟机对方法区的垃圾收集方法,jvm卸载类的断定条件以下:
只有三个条件都知足,jvm才会在垃圾收集的时候卸载类。显然,单例的类不知足条件一,所以单例类也不会被卸载。也就是说,只要单例类中的静态引用指向jvm堆中的单例对象,那么单例类和单例对象都不会被垃圾收集,依据根搜索算法,对象是否会被垃圾收集与未被使用时间长短无关,仅仅在于这个对象是否是“活”的。假如一个对象长久未使用而被回收,那么收集算法应该是最近最长未使用算法,最近最长未使用算法通常用在操做系统的内外存交换中,若是用在虚拟机垃圾回收中,岂不是太不安全了?以上是笔者的观点。
所以笔者的观点是:在hotspot虚拟机1.6版本中,除非人为地断开单例中静态引用到单例对象的联接,不然jvm垃圾收集器是不会回收单例对象的。