从排查一个登录问题看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

 

posted @ 2018-01-17 14:11  此生重演  阅读(324)  评论(0编辑  收藏  举报