目錄:java
1. 一道面試題的引出面試
在面試BAT這種一線大廠時,若是面試官問道:字符串在 JVM 中如何存放?大多數人能順利的給出以下答案:app
字符串對象在JVM中可能有兩個存放的位置:字符串常量池或堆內存。jvm
可是若是能針對上述回答,作進一步擴展,會給你的面試表現加分很多,讓你從一大波候選人中脫穎而出。下面就一塊兒來分析一下。源碼分析
首先來看,String提供了一個API, java.lang.String.intern(),這個API能夠手動將一個字符串對象的值轉移到字符串常量池中對象
在1.7以前,字符串常量池是在PermGen區域,這個區域的大小是固定的,不能在運行時根據須要擴大,也不能被垃圾收集器回收,所以若是程序中有太多的字符串調用了intern方法的話,就可能形成OOM。blog
在1.7之後,字符串常量池移到了堆內存中,而且能夠被垃圾收集器回收,這個改動下降了字符串常量池OOM的風險。內存
2. 案例分析字符串
驗證代碼:源碼
3. intern源碼分析
咱們來看intern方法的實現,intern方法的底層是一個native方法,在Hotspot JVM裏字符串常量池它的邏輯在註釋裏寫得很清楚:
若是常量池中有這個字符串常量,就直接返回,不然將該字符串對象的值存入常量池,再返回。
這裏以Openjdk1.8的源碼爲例,跟下intern方法的底層實現,String.java文件對應的C文件是String.c:
JVM_InternString這個方法的定義在jvm.h,實如今jvm.cpp中,在JVM中,Java世界和C++世界的鏈接層就是jvm.h和jvm.cpp這兩文件。
能夠看出,字符串常量池在JVM內部就是一個HashTable,也就是上面代碼中的StringTable。
從 StringTable::intern方法跟下去,能夠發現:若是找到了此次操做的字符串,就直接返回found_string;若是沒有找到,就將當前的字符串加入到HashTable中,而後再返回。
4. 總結
在Java應用恰當得使用String.intern()方法有助於節省內存空間,可是在使用的時候,也須要注意,由於StringTable的大小是固定的,若是常量池中的字符串過多,會影響程序運行效率。