聊聊jvm的StringTable及SymbolTable

本文主要研究一下jvm的StringTable及SymbolTablehtml

StringTable及SymbolTable

JDK的變更

在java7的時候將字符串常量池移到java heap,字符串常量池被限制在整個應用的堆內存中,在運行時調用String.intern()增長字符串常量不會使永久代OOM了。使用-XX:StringTableSize能夠設置StringTableSize,默認是65536

java8的時候去除PermGen,將其中的方法區移到non-heap中的Metaspace,於是SymbolTable也跟隨Metaspace移到了non-heap中java

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中

查看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能夠在運行時查看

查看SymbolTable

/ # 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能夠在運行時查看

同時查看StringTable及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;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中的SymbolTable

doc

相關文章
相關標籤/搜索