【JVM】spring单例内存管理简单分析

本文探讨了Spring框架中单例bean的内存管理与设计模式中单例的区别。Spring通过DefaultSingletonBeanRegistry管理bean实例,保存在ConcurrentHashMap中。控制器类如HelloController的实例和成员变量内存分布不同:静态变量如logger存储在方法区,非静态变量如view存储在堆中。Spring的单例对象生命周期与容器同步,成员变量是否static不影响使用。
【JVM】spring单例内存管理简单分析

问题描述:
spring框架中controller类实例为单例
开发过程中,在controller中定义的成员变量是否添加 static 描述符,在内存管理上会有区别吗?

设计模式中单例的一个例子:

public class Singleton {
    private static Singleton sing = new Singleton();
   
    private Singleton() {}
    public static Singleton getInstance() {
        return sing ;
    }
    
}
设计模式里的单例内存管理情况如下:
Singleton的类信息会保存在方法区内,包括类名,类属性等
 private static Singleton sing  这个静态变量也保存在方法区
new Singleton();  生成的对象实例保存在堆中
在堆中会创建Singleton类的Class实例作为该类信息的引用入口

比如在一个方法中有这样的语句:Singleton a = Singleton.getInstance();
getInstance() 通过这个方法所获得的是指向堆中保存的已经存在的实例的引用
Singleton a 这个变量保存在当前线程的局部变量表中,属于线程私有的 

设计模式中的单例,需要程序员显示的在堆中分配内存保存该实例


在spring中的singleton与设计模式的singleton有所差别
spring是针对一个IOC容器维持一个bean实例
而设计模式则是对一个classloader所载入的类的一个实例

在spring中,controller实例为单例,即在spring IOC中只维护了一个controller实例
具体实现是,在IOC容器中通过 DefaultSingletonBeanRegistry类 来管理的
其中关联的数据结构为:
/** Cache of singleton objects: bean name --> bean instance */
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();

一个controller 类定义:
public class HelloController implements Controller{
   
    private String view;
    private static Logger logger = Logger.getLogger(HelloController.class.getName());
     //private Logger logger = Logger.getLogger(HelloController.class.getName());

    @Override
    public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1)
            throws Exception {
        logger.info("handleRequest " + this.getClass().getName());
        String hi = arg0.getParameter( "test");
        //throw new IOException();
        return new ModelAndView(view, "test", hi);
    }
   
    public void setView(String view) {
        this.view = view;
    }
}
该controller 类的内存管理如下:
描述 HelloController 的类信息保存在方法区
描述 view 变量的信息保存在运行时常量区
描述 logger 变量的信息及其引用值保存在方法区
同样在堆中也会创建该controller类的Class实例

在spring中,我们不需要直接的 new 的操作去创建controller的实例
程序执行过程会由IOC容器分配内存保存controller实例并进行维护
这个controller实例保存在一个Map中,这个Map也是在堆中进行维护的
同时controller实例对象的引用的维护也不需要我们来考虑,spring框架会为我们进行处理

回到最初的问题,在HelloController中,定义了static变量 logger 
logger 变量 和 view 变量之间的差别是什么?
明显差别是两者保存的地方是不同的
对于view变量,由于其为对象成员变量,因此会与实例对象保存在堆中
而logger为static,则会保存在方法区中,且只有一份实例

在实际执行的过程中,由于spring所维护的controller为单例
即对于spring程序上下文来说,只存在一份controller实例
不同线程获取该实例进行处理时,实际上是对同一份内存区域进行处理

而spring 的生命周期与程序的生命周期对应,因此spring IOC所维护的各个对象实例的生命周期也与程序一样

因此造成controller的单例对象及其内的成员变量也具有伪“static”的属性
在内存中仅有一份,这里的一份是对于当前spring IOC容器来说

也就是说spring所维护的单例对象是堆中的对象,且该对象在spring IOC容器存活过程中都会存在
对于对象内的成员变量,是否声明为static,对于变量的使用并没有影响
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值