大家都知道,類被加載到JVM是放在所謂的方法區: JDK7之前是持久代(PermGen),JDK7開始是元空間(metaspace)。所以不免也會簡單地認為,類的成員變量(變量本身,而不是變量指向的對象)也是分配在方法區里。
本篇呢,就通過HSDB這個工具,來分析下類的靜態變量到底在哪里分配,同時熟悉下如何使用HSDB這個工具查看Java內存信息。
一、啟動Java進程
我們通過debug模式運行如下代碼,將斷點放在打印System.out.println("test")這一行:
package hsdb public class Test { static Test t1 = new Test(); public static void main(String[] args)throws Exception { System.out.println("test");//此行打斷點 } }
二、啟動HSDB
通過如下命令啟動HSDB:
sudo java -cp .:$JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB
會彈出如下窗口:
執行jps -ml獲取上邊我們運行的Test類的pid,然后在HSDB窗口點擊File-->Attach to HotSpot process,輸入Test的pid,點擊ok。
三、分析
現在我們的HSDB已經連接上了我們的Test進程。如下圖:
選擇Tools-->Object Histogram,可以看到Test進程里的所有對象列表,如圖:
輸入我們的Test類的類名,找到Test類的實例對象,然后雙擊。得到對象所在內存的地址,如下圖:
有了Test對象所在的內存地址后,我們就可以反向查找:誰擁有指向Test對象的引用。點擊Windows-->Console打開控制台,按enter后執行"revptrs Test對象地址" 命令,如下圖:
從結果中我們可以看到,是一個Class類型的對象里有一個指向Test對象的引用。這個Class類型的對象地址是0x0000000795786878
通過Class類型的對象地址,我們查看下Class類型對象的內容。
點擊HSDB窗口Tools-->Inspector,然后輸入Class類型對象的地址后敲enter,得到如下圖:
我們可以看到,在Class類型的對象里,確實有一個t1變量指向了Test對象,通過指向的地址,可以判斷就是我們之前搜索到的Test類型的對象。
到這里我們知道了,t1這個類成員變量,被放在了Class類型的對象里,我們只要確定這個Class類型對象所在內存的位置,也就知道了t1變量所在內存的位置。
點擊Tools-->Heap Parameters 顯示堆內存的地址范圍,如下圖:
通過比較Class類型對象的地址,我們可以看出,Class類型的對象分配在了新生代,即Java堆里,而不是方法區。