大家都知道,類被加載到JVM是放在所謂的方法區(qū): JDK7之前是持久代(PermGen),JDK7開始是元空間(metaspace)。所以不免也會簡單地認(rèn)為,類的成員變量(變量本身,而不是變量指向的對象)也是分配在方法區(qū)里。
本篇呢,就通過HSDB這個工具,來分析下類的靜態(tài)變量到底在哪里分配,同時熟悉下如何使用HSDB這個工具查看Java內(nèi)存信息。
一、啟動Java進(jìn)程
我們通過debug模式運(yùn)行如下代碼,將斷點(diǎn)放在打印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");//此行打斷點(diǎn)
}
}
二、啟動HSDB
通過如下命令啟動HSDB:
sudo java -cp .:$JAVA_HOME/lib/sa-jdi.jar sun.jvm.hotspot.HSDB
會彈出如下窗口:

執(zhí)行jps -ml獲取上邊我們運(yùn)行的Test類的pid,然后在HSDB窗口點(diǎn)擊File-->Attach to HotSpot process,輸入Test的pid,點(diǎn)擊ok。
三、分析
現(xiàn)在我們的HSDB已經(jīng)連接上了我們的Test進(jìn)程。如下圖:

選擇Tools-->Object Histogram,可以看到Test進(jìn)程里的所有對象列表,如圖:

輸入我們的Test類的類名,找到Test類的實(shí)例對象,然后雙擊。得到對象所在內(nèi)存的地址,如下圖:

有了Test對象所在的內(nèi)存地址后,我們就可以反向查找:誰擁有指向Test對象的引用。點(diǎn)擊Windows-->Console打開控制臺,按enter后執(zhí)行"revptrs Test對象地址" 命令,如下圖:

從結(jié)果中我們可以看到,是一個Class類型的對象里有一個指向Test對象的引用。這個Class類型的對象地址是0x0000000795786878
通過Class類型的對象地址,我們查看下Class類型對象的內(nèi)容。
點(diǎn)擊HSDB窗口Tools-->Inspector,然后輸入Class類型對象的地址后敲enter,得到如下圖:

我們可以看到,在Class類型的對象里,確實(shí)有一個t1變量指向了Test對象,通過指向的地址,可以判斷就是我們之前搜索到的Test類型的對象。
到這里我們知道了,t1這個類成員變量,被放在了Class類型的對象里,我們只要確定這個Class類型對象所在內(nèi)存的位置,也就知道了t1變量所在內(nèi)存的位置。
點(diǎn)擊Tools-->Heap Parameters 顯示堆內(nèi)存的地址范圍,如下圖:

通過比較Class類型對象的地址,我們可以看出,Class類型的對象分配在了新生代,即Java堆里,而不是方法區(qū)。