首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • String a = "haha"中的"haha"和a到底在堆中还是栈中还是其他区域,达人们都来讨论下。
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:32:26 楼主
    下面是String a = "haha" 的虚拟机指令:
    public class com.zte.TestJP extends java.lang.Object{
    public com.zte.TestJP();
      Code:
      0:  aload_0
      1:  invokespecial  #8; //Method java/lang/Object." <init>":()V
      4:  return

    public static void main(java.lang.String[]);
      Code:
      0:  ldc    #16; //String haha 
      2:  astore_1
      3:  return

    }

    上面红色三个指令是String a = "haha"的指令。
    大家讨论一下,对于String a = "haha"这句话中的"haha"值在栈中还是在堆中,a在堆中还在栈中。


    40  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:34:191楼 得分:0
    跟着接点分
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:36:342楼 得分:0
    头哈晕。。。指令看不懂。。。

    我觉得haha在堆中 a只是个引用 在栈中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:38:013楼 得分:0
    mark
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:40:114楼 得分:0
    haha应该是在堆中,而a是在栈中,他所存放的就是指向堆中haha的一个引用
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:42:195楼 得分:0
    我个人的理解是:
    “haha”是在常量池中,而常量池是位于JVM内存模型的方法区中,方法区的空间是在堆中开辟的,故"haha"是在堆中。
    对于String a = "haha"中的a,它的值是在执行ldc指令的时候,JVM将"haha"在堆中的一个中间地址tmp复制到栈中,并指向a。
    故a的值是在栈中。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:43:026楼 得分:0
    所有的对象都在堆中咩,无论它是否是常量池中的常量对象.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:44:407楼 得分:0
    请达人最好给大家通过JVM的指令来针对内存分配来讲一下该语句String a = "haha" 的整个过程。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:44:558楼 得分:0
    Java中除去8种基本类型,其他的都是类对象及其引用.

    栈: 对象引用,基本类型.

    堆: 所有的类对象.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:50:359楼 得分:0
    有朋友是这样理解:String a = "haha"的,另有见解的XDJM可以提出反驳,谢谢!

    (1)先定义一个名为str的对String类的对象引用变量:String str;

    (2)在中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。

    (3)将str指向对象o的地址


    对于上面3句话中,我想说的是,应该将红色的栈换成堆才对,这是我的理解!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:54:1310楼 得分:0
    有朋友是这样理解:String a = "haha"的,另有见解的XDJM可以提出反驳,谢谢!

    (1)先定义一个名为str的对String类的对象引用变量:String str;

    (2)在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"haha"的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"haha"的地址,则查找对象o,并返回o的地址。

    (3)将str指向对象o的地址


    对于上面3句话中,我想说的是,"haha"的值是存在堆中。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 09:55:1811楼 得分:0
    汗,一下9楼第二点.

    补充一句咩: String不在Java的8种基本类型中,所有的String都是对象.
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:02:5812楼 得分:0
    根据scjp学习指南里边所说
    为了使java更高效的使用内存 JVM留出一块特殊的内存区域
    称作"String常量池"
    String对象应该是在类似于堆的一块特殊内存区域中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:05:5313楼 得分:0
    继续等待达人的见解!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:20:5914楼 得分:0
    学习中。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:26:4715楼 得分:0
    haha应该是在堆中,而a是在栈中,a是对象的引用
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:27:3616楼 得分:0
    继续等待达人从虚拟机指令的角度解释一下!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:45:2617楼 得分:0
    Java中所有的基本类型都存在栈中,对象都存在堆中。
    记住这点就明白了
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:48:3818楼 得分:0
    你感觉,你研究这个,有意思吗,在哪能咋的阿
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • xql80329
    • 等级:
    发表于:2008-05-09 10:48:5219楼 得分:0
    a 在堆中  "haha"在栈中
    你再给a赋个值
        a="oyes";  a 的值是哪个?  这就是先进先出
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 10:49:0920楼 得分:0
    引用 17 楼 yefengzjfc 的回复:
    Java中所有的基本类型都存在栈中,对象都存在堆中。
    记住这点就明白了
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • xql80329
    • 等级:
    发表于:2008-05-09 10:58:1421楼 得分:0
    更正: a在栈中,"haha"在堆中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • xql80329
    • 等级:
    发表于:2008-05-09 11:00:5722楼 得分:0
    栈的优势是:存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享。堆的优势是:可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。
              但缺点是,由于要在运行时动态分配内存,存取速度较慢。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 11:48:4023楼 得分:0
    "haha"在Data segment,a在栈中!!
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • norwolfli
    • 等级:
    发表于:2008-05-09 11:56:3924楼 得分:0
    a和haha都在常量池中。

    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 12:11:5625楼 得分:0
    引用 18 楼 moodoasis 的回复:
    你感觉,你研究这个,有意思吗,在哪能咋的阿


    怎么没意思,学习东西就是要刨根问底,学一半多没劲,大家一起来讨论,请熟悉虚拟机指令以及内部运作的朋友来说说你们的看法!谢谢
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 12:35:1426楼 得分:0
    过来学习一下
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 13:05:2927楼 得分:0
    haha在堆中,a在栈中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 13:15:0228楼 得分:0
    具体的数据存放于堆
    对应的该数据对象的应用存放于栈
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 14:25:0529楼 得分:0
    楼主要想形成一次深入讨论,必须提出自己的分析和见解,不能"呼唤"别人.你没发现你的提问简单,带来的回复也是很简单吗? 而且这个类似的问题提过无数无数遍了,你也没有给出引用... 做楼主不是那么容易的
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • cchaha
    • 等级:
    发表于:2008-05-09 15:17:4530楼 得分:0
    下面是从原来类似帖子的讨论中摘要下来的:

    String a=new String("gg")不只是在堆中创建
    准确的说是在堆中创建“gg”,然后复制到栈中的a对象中,这就是复制过程
    而String str="abc";是直接在栈中创建(ghyghost认为有待参考文献)

    所以,无论是String str="abc";中的str
    还是String a=new String("gg")中的a
    都是在创建它们的类或者线程的私有栈中生存,其生存周期同创建它们类或线程
    当创建它们的类或线程死掉,它们也从栈中弹出,私有变量栈消失

    关于这个问题可以看看java rules里面有涉及,但翻译的太烂,所以也不是很详细
    最简单的做法运用IDE跟踪
    Optimizeit配合JBuilder可以看到
    在Optimizeit可以跟踪堆变量
    在JBuilder中可以跟踪栈变量,跑一个程序看看就知道了

    另外,只有String是在堆中创建,然后复制到栈中的
    其他的基本类型都是在堆中创建然后传引用到栈中的
    也就是说栈中都是引用,只有String要复制过来

    对于String类型,在java中是个及其特殊的类型
    在虚拟机的实现上
    在一个类装载的时候,不管是明确还是隐含(主动的初始化过程)
    虚拟机首先在堆中为对象的实例变量分配内存
    所有对象中和它超类中的变量都要分配内存

    并在类的变量池中对栈中的符号引用进行解析
    解析成堆内存中实际地址的指针(也就是把内存地址和符号名称一一对上号)
    解析阶段是类连接的最后阶段,也是最重要的连接阶段
    目的就是为了把符号引用替换成直接引用
    而这些符号引用就是在栈中的变量地址

    下面说到重点了:
    对于String变量
    也和其他变量一样进行这样的初始化过程
    然后在常量池中进行转换
    但不同的是java虚拟机针对String类型在内存中单独有一个符号引用到直接引用(指针)的对应表,这个表是全局的
    这个表对所有在虚拟机中出现过的String对象保留他们的引用转换
    以后,再生成一个与表中已经保留过的String对象值相同的String实例
    那么用String a = "asdf";方法生成的话,栈中的符号引用a指向的是这个全局String表,在这里进行符号引用到指针的转换
    如果使用String a = new String("asdf");方法生成的话,那么栈中的符号引用指向的是调用该方法的对象的常量池,在那里进行符号引用到指针的转换

    而使用String.intern()方法则可以将一个String类的保存到这个全局String表中
    如果具有相同值的Unicode字符串已经在这个表中,那么该方法返回表中已有字符串的地址
    如果在表中没有相同值的字符串,则将自己的地址注册到表中

    下面的程序解释了我上面所说的话:

      String a = new String("asdf");
      String b = new String("asdf");
      String f = "asdf";
      System.out.println(b == a);
      System.out.println(f == a);
      a = a.intern();
      System.out.println(b == a);
      System.out.println(f == a);
      b = b.intern();
      System.out.println(b == a);

    返回为:
    false
    false
    false
    true
    true
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 16:06:0431楼 得分:0
    java 中所有的引用变量都是被放到栈中,所有的对象都被放到了堆中

    String a = "haha";

    a 是一个引用变量
    字符串"haha" 是一个字符串对象,被放到堆中
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 22:24:2632楼 得分:0
    java 中所有的引用变量都是被放到栈中,所有的对象都被放到了堆中

    a 是一个引用变量,放到栈中
    字符串"haha" 是一个字符串对象,被放到堆中

    其实虚拟机也就是虚拟的操作系统环境,应该跟操作系统的处理一致的。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2008-05-09 23:29:1733楼 得分:0
    晚上查了一下《深入JAVA虚拟机》书中的相关内容,在描述之前,先了解一下JVM运行时数据区的内存模型。
    由《深入JAVA虚拟机》书中描述得出:JVM运行时数据区的内存模型由五部分组成
    【1】方法区
    【2】堆
    【3】JAVA栈
    【4】PC寄存器
    【5】本地方法栈

    下面开始该贴谈一下自己的理解和描述:
    针对String a = "haha" 这句话的虚拟机指令:
        0:  ldc    #16; //String haha   
        2:  astore_1
        3:  return


    谈谈自己的理解之前,我先从《深入JAVA虚拟机》书中摘一些指令的执行过程。

    下面蓝色部分字体是摘自《深入JAVA虚拟机》书中的描述:
    ldc指令的过程:要执行ldc指令,JVM首先查找16号索引所指定的常量池入口,在16号索引所指向的常量池入口,JVM将会查找CONSTANT_Integer_info,CONSTANT_Float_info和CONSTANT_String_info入口。如果还没有这些入口,JVM会解析它们。而对于上面的hahaJVM会找到CONSTANT_String_info入口,同时,将把指向被拘留String对象(由解析该入口的进程产生)的引用压入操作数栈。

    astore_1指令的过程:要执行astore_1指令,JVM从操作数栈顶部弹出一个引用类型或者returnAddress类型值,然后将该值存入由索引1指定的局部变量中字。

    return 指令的过程:返回结束程序

    谈一下我个人理解:从上面的ldc指令的执行过程可以得出:a的值是来自被拘留String对象(由解析该入口的进程产生)的引用,即可以理解为是从被拘留String对象的引用复制而来的,故我个人的理解是a的值是存在栈当中。

    刚谈了针对a的值得存储位置的个人理解,接着是对于"haha"值的个人理解:
    我们知道,对于String a = "haha" 其中"haha"值在JAVA程序运行期就确定下来了。简单一点说,就是haha的值在程序编译成class文件后,就在class文件中生成了(大家可以用UE编辑器或其它文本编辑工具在打开class文件后的字节码文件中看到这个haha值)。执行JAVA程序的过程中,第一步是class文件生成,然后被JVM装载到内存执行。那么JVM装载这个class到内存中,其中的haha这个值,在内存中是怎么为其开辟空间并存储在哪个区域中呢?

    说到这里,我们不妨先来了解一下JVM常量池这个结构,《深入JAVA虚拟机》书中是这样说的:

    常量池 虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和方法的符号引用。
    对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的,对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。说到这里,应该我想应该对常量池中的字符串值的存储位置有个大致的了解了吧。

    在介绍完JVN常量池的概念后,接着谈开始提到的"haha"的值的内存分布的位置。对于haha的值,实际上是在class文件被JVM装载到内存当中并被引擎在解析ldc指令并执行ldc指令之前,JVM就已经为haha这个字符串在常量池的CONSTANT_String_info表中分配了空间来存储haha这个值。

    注明:“对于haha的值,实际上是在class文件被JVM装载到内存当中并被引擎在解析ldc指令并执行ldc指令之前,JVM就已经为haha这个字符串在常量池的CONSTANT_String_info表中分配了空间来存储haha这个值。”这句话,是我个人根据ldc指令的执行流程和上下文来推断的。还没有在《深入JAVA虚拟机》这本书中找到明确的答案,相关章节在接下来的日子中读到的话,再给大家贴出来,说明一下。当然,要是有朋友知道这个过程的话,可以和大家共享一下。

    好,那这个haha的值既然存在常量池中,根据《深入JAVA虚拟机》书中的描述:常量池是属于类型信息的一部分,类型信息也就是每一个被转载的类型,这个类型反映到JVM内存模型中是对应存在于JVM内存模型的方法区中,也就是这个类型信息中的常量池概念是存在于在方法区中,而方法区是在JVM内存模型中的堆中由JVM来分配的。所,说到这里,我个人的理解描述也就结束了,所以我的理解是,haha的值是存在堆空间中的。


    修改 删除 举报 引用 回复