讨论命题:当一个单例的对象长久不用时,会不会被jvm的垃圾收集机制回收。
首先说一下为什么会产生这一疑问,笔者本人再此之前从来没有考虑过垃圾回收对单例模式的影响,直到去年读了一本书,《设计模式之禅》秦小波著。在书中提到在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
|
class Singleton {
private byte [] a = new byte [ 6 * 1024 * 1024 ];
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
} class Obj {
private byte [] a = new byte [ 3 * 1024 * 1024 ];
} public class Client{
public static void main(String[] args) throws Exception{
Singleton.getInstance();
while ( true ){
new Obj();
}
}
} |
本段程序的目的是模拟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堆中的对象,那么这个对象就是“活”的,是不可回收的。可以作为根的对象有:
- 虚拟机栈(栈桢中的本地变量表)中的引用的对象。
- 方法区中的类静态属性引用的对象。
- 方法区中的常量引用的对象。
- 本地方法栈中JNI的引用的对象。
方法区是jvm的一块内存区域,用来存放类相关的信息。很明显,java中单例模式创建的对象被自己类中的静态属性所引用,符合第二条,因此,单例对象不会被jvm垃圾收集。
虽然jvm堆中的单例对象不会被垃圾收集,但是单例类本身如果长时间不用会不会被收集呢?因为jvm对方法区也是有垃圾收集机制的。如果单例类被收集,那么堆中的对象就会失去到根的路径,必然会被垃圾收集掉。对此,笔者查阅了hotspot虚拟机对方法区的垃圾收集方法,jvm卸载类的判定条件如下:
- 该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
- 加载该类的ClassLoader已经被回收。
- 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
只有三个条件都满足,jvm才会在垃圾收集的时候卸载类。显然,单例的类不满足条件一,因此单例类也不会被卸载。也就是说,只要单例类中的静态引用指向jvm堆中的单例对象,那么单例类和单例对象都不会被垃圾收集,依据根搜索算法,对象是否会被垃圾收集与未被使用时间长短无关,仅仅在于这个对象是不是“活”的。假如一个对象长久未使用而被回收,那么收集算法应该是最近最长未使用算法,最近最长未使用算法一般用在操作系统的内外存交换中,如果用在虚拟机垃圾回收中,岂不是太不安全了?以上是本人的观点。
相关推荐
### 单例模式与垃圾回收机制 #### 一、引言 在软件开发领域,设计模式作为一种被广泛接受的最佳实践,对于提高代码质量和可维护性起着重要作用。单例模式作为23种经典设计模式之一,确保了某个类只有一个实例,并...
然而,单例模式与垃圾回收(Garbage Collection, GC)的关系就变得有趣起来,因为它涉及到内存管理。 首先,我们要理解Java的垃圾回收机制。Java的垃圾回收器主要负责自动回收不再使用的对象所占用的内存,以便有效...
单例模式是软件设计模式中的一种,它的主要...在实际应用中,还需要考虑JVM的垃圾回收机制、序列化以及测试等方面的问题,以确保单例模式的正确性和健壮性。理解并熟练运用单例模式,有助于提高代码的可维护性和效率。
设计模式之单例模式详解 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。 单例模式的实现主要是...
这个模式在Java中尤其常见,因为Java的垃圾回收机制允许对象长时间驻留在内存中,使得单例模式能够有效地管理资源。 在单例模式中,类的实例化过程被控制,防止了多线程环境下的多个实例产生,从而避免了潜在的共享...
5. **对象状态丢失风险**:如果长时间未使用单例对象,可能会被垃圾回收机制回收,导致对象状态丢失。 #### 五、单例模式的不同实现方式 ##### 1. 饿汉模式(Eager Initialization) 饿汉模式是最简单的单例模式...
4. 如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,下次再使用时将产生实例化新的对象,影响性能。 五、单例模式的应用场景 1. 控制资源的访问,如数据库连接池。 2. 日志服务,系统中只需要一个日志...
在描述中提到,传统的单例模式实现往往在程序运行结束时才会释放单例对象,即使在具有垃圾回收机制的语言如C#中也是如此。这种情况下,当系统切换到不使用特定单例对象的功能模块时,这些不再需要的单例仍然占用内存...
此外,考虑到.NET框架中的垃圾回收机制,当应用程序域(AppDomain)销毁时,单例也需要被正确清理,以防止内存泄漏。在Unity等游戏引擎中,可能还需要处理单例在游戏对象销毁时的特殊情况。 总之,单例模式是软件...
在这个场景中,我们关注的是“单例模式”以及与操作系统相关的“进程管理”。 单例模式是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。这种模式在系统中需要一个全局共享的唯一对象时特别有用...
1. **单例对象是否会被垃圾回收**:在正常情况下,只要静态引用未被清除,单例对象就不会被垃圾回收。 2. **JVM中是否会存在多个单例**:在同一个JVM中,使用反射等手段可能产生多个单例对象。 3. **懒汉式单例是否...
3. 如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,下次再使用时需要重新实例化,可能影响性能。 四、使用场景 1. 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。 2. 当这个唯一...
Java 基础难点是 Java 开发中的一些核心概念和技术点,本节总结了 Java 中的面向对象编程、接口和继承、内部类、单例模式、垃圾回收、克隆等知识点。 一、接口和继承 在 Java 中,接口和继承是两个核心概念。接口...
2. 单例模式:确保一个类只有一个实例,并提供全局访问点。 3. 建造者模式:将复杂对象的构建与其表示分离,使同一个构建过程可以创建不同表示。 4. 代理模式:为其他对象提供一种代理以控制对这个对象的访问。 5. ....
本文件主要内容是前端的三种设计模式:单例模式,发布-订阅模式,策略模式,以及浏览器的垃圾回收机制,适合已经学习完了js基础的小伙伴(js基础部分可以看我前面的专栏——js每日一学),感兴趣的小伙伴可以自行...
常见的内存泄漏场景包括静态集合中存储的无用对象、单例模式下的长期存在的引用等。 - **示例代码**:上述代码展示了如何使用`finally`块确保文件流在使用完毕后被正确关闭,防止资源泄漏。 6. **垃圾回收的优化**...
在一些语言中,单例类负责内存管理,但若其他对象持有单例对象的引用,可能导致单例对象无法被垃圾回收。 通过使用单例模式,开发者可以控制对象的实例化过程,并提供一个全局访问点,简化对共享资源的访问。但同时...
* 单例模式可能会导致内存泄露,因为单例对象不会被垃圾回收。 * 单例模式可能会导致线程安全问题,因为多个线程可能会同时访问同一个单例对象。 * 单例模式可能会导致耦合度高的问题,因为单例对象可能会与其他对象...
在Android系统中,垃圾回收(Garbage Collection, GC)机制是管理内存的重要组成部分,它自动回收不再使用的对象,以防止内存泄漏。这份“Android垃圾回收实质内容解析实用教案”主要探讨了Android中智能指针的使用...