- 类加载 demo 1
public class Test_1 { public static void main(String[] args) { System.out.printf(Test_1_B.str); } } class Test_1_A { public static String str = "A str"; static { System.out.println("A Static Block"); } } class Test_1_B extends Test_1_A { static { System.out.println("B Static Block"); } } //输出结果 //A Static Block //A str
4. 读取静态属性的实现
Java 代码如下:
public class Test_1 { public static void main(String[] args) { System.out.printf(Test_1_B.str); } } class Test_1_A { public static String str = "A str"; static { System.out.println("A Static Block"); } } class Test_1_B extends Test_1_A { static { System.out.println("B Static Block"); } }
静态字段如何存储, 有两个核心的概念在 JVM 1.8 以前存储在 instanceKlass
jdk1.8 是存储在 instanceMirrorKlass
只中的
Test_1_A的
静态变量str的值存放在StringTable中,镜像类中存放的是字符串的指针
Test_1_B中
str是类Test_1_A的静态属性,可以看到不会存储到子类Test_1_B的镜像类中 可以猜得到,通过子类Test_1_B访问父类Test_1_A的静态字段有两种实现方式:
1、先去Test_1_B的镜像类中去取,如果有直接返回;如果没有,会沿着继承链将请求往上抛。很明显,这种算法的性能随继承链的death而上升,算法复杂度为O(n)
2、借助另外的数据结构实现,使用K-V的格式存储,查询性能为O(1)
Hotspot就是使用的第二种方式,借助另外的数据结构ConstantPoolCache,常量池类ConstantPool中有个属性_cache指向了这个结构。每一条数据对应一个类ConstantPoolCacheEntry。
ConstantPoolCacheEntry在哪呢?在ConstantPoolCache对象后面,看代码 \openjdk\hotspot\src\share\vm\oops\cpCache.hpp
ConstantPoolCacheEntry* base() const { return (ConstantPoolCacheEntry*)((address)this + in_bytes(base_offset())); }
这个公式的意思是ConstantPoolCache对象的地址加上ConstantPoolCache对象的内存大小 ConstantPoolCache 常量池缓存是为常量池预留的运行时数据结构。保存所有字段访问和调用字节码的解释器运行时信息。缓存是在类被积极使用之前创建和初始化的。每个缓存项在解析时被填充 如何读取 \openjdk\hotspot\src\share\vm\interpreter\bytecodeInterpreter.cpp
CASE(_getstatic): { u2 index; ConstantPoolCacheEntry* cache; index = Bytes::get_native_u2(pc+1); // QQQ Need to make this as inlined as possible. Probably need to // split all the bytecode cases out so c++ compiler has a chance // for constant prop to fold everything possible away. cache = cp->entry_at(index); if (!cache->is_resolved((Bytecodes::Code)opcode)) { CALL_VM(InterpreterRuntime::resolve_get_put(THREAD, (Bytecodes::Code)opcode), handle_exception); cache = cp->entry_at(index); } ……
从代码中可以看出,是直接去获取ConstantPoolCacheEntry
5. 常用工具
1. 字节码查看 idea 插件 jclasslib
效果如下:
2. HSDB JDK 自带插件
- 使用方式
# jdk 安装目录下执行 # 这里注意需要加一个 sudo 在 macos 上可能存在权限问题 sudo java -cp lib/sa-jdi.jar sun.jvm.hotspot.HSDB
3. javap 命令
查看字节码和反编译信息
javap -v xxx