【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,对于变量的使用并没有影响