spring容器不被gc的背后惊天秘密
1.spring容器会被gc吗?
笔者认为,倘若在项目运行过程中,spring容器被垃圾回收,那整个项目将不可用。所以,spring容器是肯定不会被垃圾回收的!
2,那如何保证不被gc呢?
说到gc,就要了解什么是gc root。
gc root 一共包含以下几类:
- System class:被bootstrap或者system类加载器加载的类,比如rt.jar里的java.util.*;
- JNI global:native代码里的global变量;
- JNI local:native代码里的local变量,比如用户定义的JNI代码和JVM的内部代码;
- Thread:已经启动并且没有stop的线程;
- Thread block:当前活跃的线程block中引用的对象;
- busy monitor:被调用了wait()或者notify()或者被synchronized同步的对象,如果是synchronized方法,那么静态方法指的类,非静态方法指的是对象;
- java local:local变量,比如方法的入参和方法内创建的变量;
- native stack:native代码里的出入参数,比如file/net/IO方法以及反射的参数;
- finalizable:在一个队列里等待它的finalizer 运行的对象;
- unfinalized:一个有finalize方法的对象,还没有被finalize,同时也没有进入finalizer队列等待finalize;
- unreachable:不会被触碰到的对象,在MAT里被标记为root用来retain object,否则是不会在分析中出现的;
- java stack frame:java栈帧包含了本地变量,当dump被解析时且在preferences里设置过把栈帧当做对象,这时才会产生;
在heap内存不足时,jvm会根据gc root进行可达性探测,没被标记的对象,会被垃圾回收!
3,spring的gc root 推断
随意启动一个spring项目,控制台输入以下命令生成堆内存快照
jmap -dump:format=b,file=/usr/local/gc/dump.hprof {pid}
通过MAT工具进行分析:
找到spring 工厂,path to root
通过图中信息分析,一切就明了了。spring 其gc root 为 Thread,根据图中信息可推断此线程为Tomcat启动,加载容器的线程,此线程未stop,即spring 资源无法被回收!
若想springbean 被回收,可手动调用close方法,将bean 与容器关系隔离,即可回收,笔者在此就不做演示了。