聊聊jvm的StringTable及SymbolTable
序
本文主要研究一下jvm的StringTable及SymbolTable
StringTable变动
在java7的时候将字符串常量池移到java heap,字符串常量池被限制在整个应用的堆内存中,在运行时调用String.intern()增加字符串常量不会使永久代OOM了。使用-XX:StringTableSize可以设置StringTableSize,默认是65536
查看StringTable
jcmd pid VM.stringtable
/ # jcmd 1 VM.stringtable 1: StringTable statistics: Number of buckets : 65536 = 524288 bytes, each 8 Number of entries : 23407 = 374512 bytes, each 16 Number of literals : 23407 = 2153344 bytes, avg 91.996 Total footprsize_t : = 3052144 bytes Average bucket size : 0.357 Variance of bucket size : 0.360 Std. dev. of bucket size: 0.600 Maximum bucket size : 5
- 使用jcmd pid VM.stringtable可以在运行时查看
-XX:+PrintStringTableStatistics
SymbolTable statistics: Number of buckets : 32768 = 262144 bytes, each 8 Number of entries : 129218 = 2067488 bytes, each 16 Number of literals : 129218 = 7173384 bytes, avg 55.514 Total footprsize_t : = 9503016 bytes Average bucket size : 3.943 Variance of bucket size : 3.998 Std. dev. of bucket size: 2.000 Maximum bucket size : 14 StringTable statistics: Number of buckets : 65536 = 524288 bytes, each 8 Number of entries : 23467 = 375472 bytes, each 16 Number of literals : 23467 = 2157192 bytes, avg 91.924 Total footprsize_t : = 3056952 bytes Average bucket size : 0.358 Variance of bucket size : 0.360 Std. dev. of bucket size: 0.600 Maximum bucket size : 5
- 启动时添加-XX:+PrintStringTableStatistics参数,在jvm进程退出时会输出SymbolTable statistics及StringTable statistics
SymbolTable( symbolic references in Runtime Constant Pool )
- 一个完整的类加载过程必须经历加载( Loading )、连接( Linking )、初始化( Initialization)这三个步骤
- 其中类加载阶段就是由类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,然后将其转换为一个与目标类型对应的java.lang.Class对象实例;连接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中,经由验证( Verification )、准备( Preparation )、解析( Resolution )三个阶段;初始化阶段将一个类中所有被static关键字标识的代码统一执行一遍,如果执行的是静态变量,那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值;如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作
- 在连接( Linking )步骤里头的解析( Resolution )阶段,需要将常量池中所有的符号引用( classes、interfaces、fields、methods referenced in the constant pool )转为直接引用( 得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法 )
SymbolTable这个词在传统编程语言的实现里头比较常用( This data structure serves many of the purposes of the symbol table of a conventional programming language implementation),而在jvm里头对应的是Runtime Constant Pool中的symbolic references( Runtime Constant Pool除了symbolic references还包含了static constants ),它是在类加载的时候( Resolution in Linking )根据class元数据中的constant pool table创建的,因而称为Runtime Constant Pool;这部分位于metaspcae,分配在native memory中
查看SymbolTable
jcmd pid VM.stringtable
/ # jcmd 1 VM.symboltable 1: SymbolTable statistics: Number of buckets : 32768 = 262144 bytes, each 8 Number of entries : 128885 = 2062160 bytes, each 16 Number of literals : 128885 = 7160912 bytes, avg 55.560 Total footprsize_t : = 9485216 bytes Average bucket size : 3.933 Variance of bucket size : 3.982 Std. dev. of bucket size: 1.996 Maximum bucket size : 14
- 使用jcmd pid VM.symboltable可以在运行时查看
-XX:+PrintStringTableStatistics
SymbolTable statistics: Number of buckets : 32768 = 262144 bytes, each 8 Number of entries : 129215 = 2067440 bytes, each 16 Number of literals : 129215 = 7173248 bytes, avg 55.514 Total footprsize_t : = 9502832 bytes Average bucket size : 3.943 Variance of bucket size : 3.990 Std. dev. of bucket size: 1.998 Maximum bucket size : 14 StringTable statistics: Number of buckets : 65536 = 524288 bytes, each 8 Number of entries : 23470 = 375520 bytes, each 16 Number of literals : 23470 = 2157736 bytes, avg 91.936 Total footprsize_t : = 3057544 bytes Average bucket size : 0.358 Variance of bucket size : 0.361 Std. dev. of bucket size: 0.601 Maximum bucket size : 5
- 启动时添加-XX:+PrintStringTableStatistics参数,在jvm进程退出时会输出SymbolTable statistics及StringTable statistics
jcmd pid VM.native_memory
/ # jcmd 1 VM.native_memory scale=MB 1: Native Memory Tracking: Total: reserved=1857MB, committed=112MB - Java Heap (reserved=502MB, committed=32MB) (mmap: reserved=502MB, committed=32MB) - Class (reserved=1065MB, committed=47MB) (classes #8386) ( instance classes #7843, array classes #543) (malloc=1MB #21250) (mmap: reserved=1064MB, committed=45MB) ( Metadata: ) ( reserved=40MB, committed=40MB) ( used=39MB) ( free=1MB) ( waste=0MB =0.00%) ( Class space:) ( reserved=1024MB, committed=6MB) ( used=5MB) ( free=0MB) ( waste=0MB =0.00%) - Thread (reserved=29MB, committed=3MB) (thread #29) (stack: reserved=29MB, committed=2MB) - Code (reserved=243MB, committed=15MB) (malloc=1MB #4744) (mmap: reserved=242MB, committed=14MB) - GC (reserved=2MB, committed=0MB) (mmap: reserved=2MB, committed=0MB) - Internal (reserved=1MB, committed=1MB) (malloc=1MB #2172) - Symbol (reserved=10MB, committed=10MB) (malloc=7MB #223735) (arena=3MB #1) - Native Memory Tracking (reserved=4MB, committed=4MB) (tracking overhead=4MB)
- 使用jcmd pid VM.native_memory输出的Symbol部分包含了StringTable( interned String )及SymbolTable
小结
- 在java7的时候将字符串常量池则移到java heap,字符串常量池被限制在整个应用的堆内存中,在运行时调用String.intern()增加字符串常量不会使永久代OOM了。使用-XX:StringTableSize可以设置StringTableSize,默认是65536
- 在启动时添加-XX:+PrintStringTableStatistics参数,在jvm进程退出时会输出SymbolTable statistics及StringTable statistics
- StringTable位于heap中( java7+ ),而SymbolTable则在native memory中;使用jcmd pid VM.stringtable可以在运行时查看StringTable;使用jcmd pid VM.symboltable可以在运行时查看SymbolTable;使用jcmd pid VM.native_memory输出的Symbol部分包含了heap中StringTable( interned String )及non heap中的SymbolTable