序本文主要研究一下jvm的StringTable及SymbolTableStringTable及SymbolTableJDK的变动在java7的时候将字符串常量池移到java heap,字符串常量池被限制在整个应用的堆内存中,在运行时调用String.intern()增加字符串常量不会使永久代OOM了。使用-XX:StringTableSize可以设置StringTableSize,默认是65536java8的时候去除PermGen,将其中的方法区移到non-heap中的Metaspace,因而SymbolTable也跟随Metaspace移到了non-heap中SymbolTablesymbolic 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中查看StringTable/ # jcmd 1 VM.stringtable1:StringTable statistics:Number of buckets : 65536 = 524288 bytes, each 8Number of entries : 23407 = 374512 bytes, each 16Number of literals : 23407 = 2153344 bytes, avg 91.996Total footprsize_t : = 3052144 bytesAverage bucket size : 0.357Variance of bucket size : 0.360Std. dev. of bucket size: 0.600Maximum bucket size : 5使用jcmd pid VM.stringtable可以在运行时查看查看SymbolTable/ # jcmd 1 VM.symboltable1:SymbolTable statistics:Number of buckets : 32768 = 262144 bytes, each 8Number of entries : 128885 = 2062160 bytes, each 16Number of literals : 128885 = 7160912 bytes, avg 55.560Total footprsize_t : = 9485216 bytesAverage bucket size : 3.933Variance of bucket size : 3.982Std. dev. of bucket size: 1.996Maximum bucket size : 14使用jcmd pid VM.symboltable可以在运行时查看同时查看StringTable及SymbolTable-XX:+PrintStringTableStatisticsSymbolTable statistics:Number of buckets : 32768 = 262144 bytes, each 8Number of entries : 129215 = 2067440 bytes, each 16Number of literals : 129215 = 7173248 bytes, avg 55.514Total footprsize_t : = 9502832 bytesAverage bucket size : 3.943Variance of bucket size : 3.990Std. dev. of bucket size: 1.998Maximum bucket size : 14StringTable statistics:Number of buckets : 65536 = 524288 bytes, each 8Number of entries : 23470 = 375520 bytes, each 16Number of literals : 23470 = 2157736 bytes, avg 91.936Total footprsize_t : = 3057544 bytesAverage bucket size : 0.358Variance of bucket size : 0.361Std. dev. of bucket size: 0.601Maximum bucket size : 5启动时添加-XX:+PrintStringTableStatistics参数,在jvm进程退出时会输出SymbolTable statistics及StringTable statisticsjcmd pid VM.native_memory/ # jcmd 1 VM.native_memory scale=MB1: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;java8的时候去除PermGen,将其中的方法区移到non-heap中的Metaspace,因而SymbolTable也跟随Metaspace移到了non-heap中StringTable位于heap中(java7+),而SymbolTable则在native memory中;使用jcmd pid VM.stringtable可以在运行时查看StringTable;使用jcmd pid VM.symboltable可以在运行时查看SymbolTable在启动时添加-XX:+PrintStringTableStatistics参数,在jvm进程退出时会输出SymbolTable statistics及StringTable statistics;使用jcmd pid VM.native_memory输出的Symbol部分包含了heap中StringTable(interned String)及non heap中的SymbolTabledocJava的类加载机制Chapter 5. Loading, Linking, and Initializing5.1. The Run-Time Constant PoolUnderstanding String Table Size in HotSpot聊聊jvm的PermGen与MetaspaceWill Java’s interned strings be GCed?Garbage collection behaviour for String.intern()10 Things Every Java Programmer Should Know about StringDifference between String literal and New String object in JavaUnderstand JVM Loading, JVM Linking, and JVM Initialization