`
flychao88
  • 浏览: 743587 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

单例模式与垃圾回收

 
阅读更多

讨论命题:当一个单例的对象长久不用时,会不会被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堆中的单例对象,那么单例类和单例对象都不会被垃圾收集,依据根搜索算法,对象是否会被垃圾收集与未被使用时间长短无关,仅仅在于这个对象是不是“活”的。假如一个对象长久未使用而被回收,那么收集算法应该是最近最长未使用算法,最近最长未使用算法一般用在操作系统的内外存交换中,如果用在虚拟机垃圾回收中,岂不是太不安全了?以上是本人的观点。

分享到:
评论

相关推荐

    单例模式与垃圾回收机制

    探索讨论单例模式会不会被垃圾回收机制回收,结论是HotSpot中不会

    单例模式垃圾回收_动力节点Java学院整理

    主要为大家详细介绍了单例模式垃圾回收的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    C++中的单例模式及按需释放模型

    单例模式是设计模式中最简单最容易理解的模式之一,实用方便,项目设计开发中会被经常使用,但是不知道读者有没有考虑过这个问题,单例模式实例什么时候被释放,读者有兴趣可以仔细分析下,按照目前通常方法实现的...

    本文件涉及到js的高级部分知识点学习,主要内容是前端常见的三种设计者模式以及浏览器的垃圾回收机制,感兴趣的小伙伴可以下载自行阅读

    本文件主要内容是前端的三种设计模式:单例模式,发布-订阅模式,策略模式,以及浏览器的垃圾回收机制,适合已经学习完了js基础的小伙伴(js基础部分可以看我前面的专栏——js每日一学),感兴趣的小伙伴可以自行...

    Python七大类常见问题详解.rar

    Python七大类常见深度问题详解: Python类三种方法,函数传参,类与实例变量(一) Python迭代器生成器,私有变量及推导式(二...Python中深浅拷贝 垃圾回收与 super继承(六) Python 调度算法 死锁 静动态链接 分页分段(七)

    Java初级开发面试题

    Java虚拟机:Java内存模型、垃圾回收、类加载机制等。 常见的Java框架:Spring、Hibernate、Mybatis等。 Java设计模式:单例模式、工厂模式、代理模式等。 网络编程:TCP/IP、HTTP、Web Services等。 数据库相关...

    java经典面试题目-面经-java-Java语言的进阶概念-常用的库和框架-并发编程-网络编程-Web开发-面经

    Java中的GC(垃圾回收)是什么?如何手动触发对象的垃圾回收? 什么是Java中的设计模式?列举一些常见的设计模式。 什么是Java中的单例模式?如何实现线程安全的单例模式? 什么是Java中的生命周期回调方法?列举...

    mysql面试题-mysql经典面试题目-数据库的基本概念-SQL语法-事务处理-索引优化-性能调优-mysql-面试题目

    Java中的GC(垃圾回收)是什么?如何手动触发对象的垃圾回收? 什么是Java中的设计模式?列举一些常见的设计模式。 什么是Java中的单例模式?如何实现线程安全的单例模式? 什么是Java中的生命周期回调方法?列举...

    Python 全面的面试题

    * [16 单例模式](#16-单例模式) * [1 使⽤__new__⽅法](#1-使⽤__new__⽅法) * [2 共享属性](#2-共享属性) * [3 装饰器版本](#3-装饰器版本) * [4 import⽅法](#4-import⽅法) * [17 Python中的作⽤域](#17-...

    JAVA中级书籍

    掌握JVM内存分配、JVM垃圾回收;类装载机制; 性能优化; 反射机制;多线程;IO/NIO; 网络编程;常用数据结构和相关算法。 2、对面向对象的软件开发思想有清晰的认识、熟悉掌握常用的设计模式;设计模式;单例模式...

    java面试题.pdf

    3. Java中垃圾回收的机制是什么? 4. Java中什么是反射? 5. Java中什么是线程安全? 6. Java中抽象类和接口的区别是什么? 7. Java中什么是异常? 8. Java中如何防止对象的clone? 9. Java中什么是泛型? 10. Java...

    2024最新的面试题来了

    模块化编程与热插拔、Java单例防止反射漏洞攻击、JVM常用配置参数、线程调度器和时间分片是计算机编程中一些重要的概念和技术。 模块化编程是一种将复杂的程序分解为独立的、可重用的模块的编程方法。它提供了更好...

    JAVA超全面试突击包-答案讲义

    涵含各种重要的JAVA编程知识点,面试突击专用 内容包括:Spring、SprngBoot、SpringCloud、Redis、MySQL、MyBatis、JVM、多...设计模式:包括常见的设计模式,如单例模式,工厂模式,观察者模式等,以及它们的使用场景

    python面试常见问题

    python面试常见问题1、“==”与is的区别2、list与tuple的区别3、python中list与dict4、局部变量和全局变量5、迭代器和生成器6、yield7、import过程8、python装饰器9、python特点(封装、继承、多态)10、垃圾回收...

    北京百度java面试题大全

    Java虚拟机(JVM):包括垃圾回收机制、内存管理、类加载机制等与JVM相关的知识。 设计模式:涉及常见的设计模式,如单例模式、工厂模式、观察者模式等。 Java框架和技术:包括Spring、Hibernate、My

    2023java最新学习路线.docx

    2. 性能优化:学习分析和调优Java应用程序的性能,了解内存管理、垃圾回收、性能监测和调优工具。 3. 反射和字节码操作:学习使用Java的反射机制和字节码操作库,实现动态代理、代码生成和运行时修改类的功能。 4....

    Java基础语法面试题.docx

    Java虚拟机(JVM):涵盖内存管理、垃圾回收、类加载机制等与JVM相关的知识。 设计模式:介绍常见的设计模式,如单例模式、工厂模式、观察者模式等。 常见算法和数据结构:可能包含一些常见的算法问题,如查找、...

    java——让学员少走弯路

    Java中包的概念,类的说明符、方法的说明符、对象的销毁(JVM垃圾回收器的演示),Java中接口理解与掌握。 Java中内部类的理解、运用与掌握,Java中的异常处理。 Java的常用包,"=="和"equals"的用法,基本数据类型与...

    超全面python面试题

    16 单例模式 1 使用__new__方法 2 共享属性 3 装饰器版本 4 import方法 17 Python中的作用域 18 GIL线程全局锁 19 协程 20 闭包 21 lambda函数 22 Python函数式编程 23 Python里的拷贝 24 Python垃圾回收机制 1 引用...

    Python面试内容很多,干货满满

    16 单例模式 1使用 new 方法 2 共享属性 3 装饰器版本 4 import方法 。 17 Python中的作用域 。 18 GIL线程全局锁 。19 协程 。 20闭包 。 21lambda函数 。 22 Python函数式编程 。 23 Python里的拷贝 。 24 Python...

Global site tag (gtag.js) - Google Analytics