作为一个java程序员是不是经常有这样的疑问:java对象在jvm中什么地方?java对象在JVM里是什么模样的呢?
本节我们利用HSDB这个工具来分析一下这两个问题。首先我们写一段代码,如下:
public class Main {
public static void main(String[] args) {
User user = new User(27,"chujinhui");
System.out.println("");
}
}
class User{
private int age;
private String name;
public User(int age,String name){
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
我们在第5行,也就是输出那行加入了断点,让代码停止在第5行,以便于我们从内存中寻找创建的User对象。
cmd进入命令行,输入jps,查找当前程序的进程id如下:
我们看到当前程序的进程id是3048。
命令行继续输入:java -cp .;%JAVA_HOME%/lib/sa-jdi.jar sun.jvm.hotspot.HSDB 启动HSDB工具。
如下图:
刚打开时显示此进程中的线程信息,我们选中主线程,也就是最后一个,双击就会打开Inspector窗口
,如下图所示:
我们在文本框中输出内存地址后,下面会显示此内存地址上的数据。那么现在我们就需要找到User对象
的内存地址。
我们打开HSDB的命令行页面:windows 》 console,如下图所示:
回车后,就会显示hsdb>提示,输入universe命令,回车后会显示堆信息,如下:
hsdb> universe
Heap Parameters:
Gen 0: eden [0x10200000,0x102eb2f8,0x10650000) space capacity = 4521984, 21.30303866621377 used
from [0x10650000,0x10650000,0x106d0000) space capacity = 524288, 0.0 used
to [0x106d0000,0x106d0000,0x10750000) space capacity = 524288, 0.0 usedInvocations: 0
Gen 1: old [0x15750000,0x15750000,0x16200000) space capacity = 11206656, 0.0 usedInvocations: 0
猜想,我们的User对象应该在年轻代中,输入scanoops 0x10200000 0x10650000 User,回车后如下所示:
hsdb> scanoops 0x10200000 0x10650000 User
0x102de618 User
果真,我们在年轻代中,找到了我们的User对象,并且此对象的地址是:0x102de618,
返回Inspector窗口,在文本框中输入此地址后,如下所示:
我们现在就看到了User对象在内存中的样子,我们可以分作两部分,第一部分我们叫对象头,第二部分叫实例数据。
对象头又包括两个部分,_mark和_metadata_klass。
_mark:记录我们对象运行时的一些状态。比如,hash码,是否加锁等。
_metadata_klass:是当前类信息的指针,此指针有宽窄之分。在32位机器上是32位的,在64位机器上是64位的指针。
所以在64位机器上我们可以通过设置窄化,来节省一些内存。此指针指向的内容包含当前类的一些信息:
比如Class对象、父类、兄弟类、成员变量信息等。
实例数据:保存对象实例的数据,我们看到其中age是27,name是一个指针指向了“chujinhui”这个常量。
O了。