从排查一个登录问题看jvm类加载机制
问题来源
这段时间我们在切换某海外环境的登录体系,遇到一个应用会话校验有问题,排查过程如下:
从会话逻辑trace去看,走到了tair获取session的代码里,实例代码如下:
public class SessionManagerProxyImpl implements CnSessionManagerProxy {
private volatile static Map<String,SessionManager> sessionManagerMap = Maps.newHashMap();
public SessionResult get(String sessionId) { 。。。。 SessionManager cnSessionManager = sessionManagerMap.get(readLocation); 。。。。 }
}
通过greys的sc排查到SessionManager居然没有加载到jvm中,于是赶紧去学习了下。。。。
“加载”的定义
首先要了解下我们上面所说的“加载”的定义是什么:
jvm把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制
赶紧翻了下【深入理解jvm虚拟机】,类从被加载到jvm内存中开始,到卸载出内存为止,它的整个生命周期包括了:加载(Loading)---> 验证(Verification)--->准备(Preparation)--->解析(Resolution)--->初始化(Initialization)--->使用(using)--->卸载(Unloading)七个阶段
- 其中加载包括5个阶段:加载(Loading)---> 验证(Verification)--->准备(Preparation)--->解析(Resolution)--->初始化(Initialization)
- 在加载的过程中的3个环节称为连接(Linking):验证(Verification)--->准备(Preparation)--->解析(Resolution)
- 所以加载的过程是:加载(Loading)---> 连接(Linking)--->初始化(Initialization)
因此,我们上面sc到加载的类,这里所说的“加载”是5个阶段的的总和,而不是其中的“加载(Loading)”
加载的时机
1.遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令最常见的Java代码场景是:使用new关键字实例化对象时、读取或者设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)时、以及调用一个类的静态方法的时候。
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
3.当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要触发父类的初始化。
4.当虚拟机启动时,用户需要指定一个执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
总结
JVM加载类是一种懒加载的模式,只有在需要某个类的时候才会加载,只是声明某个类的引用而不创建对象的时候是不会加载的,因此上面的SessionManager没有加载的问题就很好解释了
参考:
http://blog.csdn.net/u010425776/article/details/51251430
http://chenzhou123520.iteye.com/blog/1597597