黑马程序员技术交流社区

标题: 对象在堆内存中的结构到底是什么样子? [打印本页]

作者: toShareBeauty    时间: 2013-7-9 10:06
标题: 对象在堆内存中的结构到底是什么样子?
本帖最后由 杨兴庭 于 2013-7-9 21:16 编辑

如题:对象在堆内存中的结构到底是什么样子?

首先感谢下面几位同学的回答,我再补充一点来把问题描述更加清楚
问题是这样的,我在研究 jvm 原理的时候,碰到如下代码:
  1. class StringDemo
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 Object s1 = new String("Hello");
  6.                 Object s2 = new String("Hello");
  7.                  
  8.                 if(s1 == s2) {
  9.                         System.out.println("s1 and s2 are ==");
  10.                 }else if (s1.equals(s2)) {
  11.                         System.out.println("s1 and s2 are equals()");
  12.                 }
  13.         }
  14. }
复制代码
我模拟 jvm 跑了一下这个程序,有些地方也不太清楚:

当加载 StringDemo 类的时候,"Hello" 是局部变量的常量,它会放在 JVM 的运行时数据区——>方法区——>appClassLoader域——>StringDemo类字节码信息——>常量池 里面么(1.在这个常量池里面,"Hello" 还是以字符串对象的形式存在么,还是引用形式,因为 String 不是 jvm 支持的8种基本数据类型,这个地方 String 是不是还要转为字符,并以字符数组的形式存在于堆内存,让后再用 字符数组 封装成 String 对象, 保存在堆内存中,常量池中保存的只是对个对象的引用)? 当 JVM 执行 StringDemo.main  函数的时候,在 Java 栈 压入 main 函数栈帧,在栈帧——>局部变量区 分配 s1 s2 两个局部变量的空间,并在栈帧的操作栈分配一个引用型存储单元,保存 "Hello" 对象的引用(2.这个引用是执行堆的对象还是只想常量池?),然后让 BootStrap Class Loader 加载 String 类,并动态修改 StringDemo 类在方法区中的常量池里面关于 String 类的符号引用为直接引用(3.这个地方是不是应该在常量池使用 String 对象的时候就做了?),之后调用 String 的构造方法,在 Java 栈 中压入 String 对应的构造函数栈帧,前面指向 "Hello" 的操作栈变量空间,暂时和 String 构造函数栈帧的局部变量共享同一份空间,此时在堆内存中给 String 类分配一个对象,jvm 执行 String 构造函数,完成后返回一个 String 对象的引用(4.这个String 对象的引用保存在哪里是 String 构造函数栈帧的局部变量区还是操作数栈),Java 栈弹出 String 构造函数 栈帧,s1 对应的栈帧的局部变量域中的内存单元指向这个 String 对象。

其他部分我基本都描述过了,但是 jvm 给一个 String对象分配内存我没有描述,因为我不知道到底 String 对象在堆内存中结构是什么样子?



作者: 郑才熹    时间: 2013-7-9 10:55
C:\Documents and Settings\Administrator\桌面\未命名.jpg
这是我自己画的,希望能够帮到你。
作者: 草貌路飞    时间: 2013-7-9 10:58
楼一有才..
作者: 杨兴庭    时间: 2013-7-9 11:15
草貌路飞 发表于 2013-7-9 10:58
楼一有才..

我也是这么觉得的。。、
作者: 杨兴庭    时间: 2013-7-9 11:16
郑才熹 发表于 2013-7-9 10:55
这是我自己画的,希望能够帮到你。

上传错误,麻烦重新上传您绘制的图。。
作者: 郑才熹    时间: 2013-7-9 11:42
额,不会添加图片啊,上面的地址是图片在我电脑上的位置。没图我就直接说吧。对象是存储在栈内存中的,而对象的属性是存放在堆内存中的。java中的内存区域除了栈内存和堆内存,还有全局数据区用来保存static类型的属性;全局代码区用来保存所有方法的定义。

作者: 郑才熹    时间: 2013-7-9 11:44
杨兴庭 发表于 2013-7-9 11:16
上传错误,麻烦重新上传您绘制的图。。

:L没传过图片啊:L,赚积分不容易啊,家里没网:'(
作者: toShareBeauty    时间: 2013-7-9 11:51
本帖最后由 toShareBeauty 于 2013-7-9 12:00 编辑
郑才熹 发表于 2013-7-9 11:44
没传过图片啊,赚积分不容易啊,家里没网

。。。,感谢哥们这么费心,下次上网再传吧,你想说的是这个图吧:

其实我想问的是,一个对象在堆里面是个什么样的结构?


然后:插图的话要用高级编辑模式:


作者: 草帽    时间: 2013-7-9 11:59
class Persom{
        String name
        Int age
        Person(String name,Int age){
                this.name=name;
                this.age=age;
        }
}

(1)用Person zhang;声明一个对象zhang时,将在栈内存为对象的引用变量zhang分配内存空间,但Person的值为空,称zhang是一个空对象。空对象不能使用,因为它还没有引用任何“实体”。
(2)对象实例化时的内存模型当执行zhang=new Person(zhangsan,20);时,会做两件事:在堆内存中为类的成员变量name、age分配内存,并将其初始化为各数据类型的默认值;接着进行显式初始化(类定义时的初始化值);最后调用构造方法,为成员变量赋值。返回堆内存中对象的引用(相当于首地址)给引用变量zhang,以后就可以通过zhang来引用堆内存中的对象了。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2