我觉得这个贴子非常好,以前学过一点c++,当时记得调用类的方法的时候会自动传一个隐含的参数,那就是this。通过robbin的讲解,我曾经很多疑惑的问题都清楚了,对初学者同样有好处,不过这个需要一些 微机原理 和 数据机构 的知识

解决方案 »

  1.   

    更正 是 数据结构  
    sorry  打错了
      

  2.   

    不错!
    不过我有个问题想问问,stack 定长,并且顺序分配!
    现在我的问题就是,
       类的静态方法在 classLoader是 push stack,那么在什么时候弹出 stack??
      

  3.   

    那对于静态的非基础类型的数据如何存放?是引用在stack中,数据在heap中?还是引用和数据都在stack中?
      

  4.   

    对于这个问题,我也没有研究过
    学汇编的时候,有寄存器是cs和ss吧
    cs:ip就构成了你现在要执行的指令地址,而当你调用函数的时候,会将当前的cs:ip值压入堆栈
    然后cs:ip就指向了你调用的函数的地址,等调用完了,在将原来的cs:ip弹出回来jvm我还真不懂
      

  5.   

    我想 静态的非基础类型的数据应该是是保存在 stack指令内存区的
      

  6.   

    我想 静态的非基础类型的数据应该是是保存在 stack指令内存区的
      

  7.   

    我也认为是放在stack中的。但这正也恰好是我的疑惑所在。如果是在stack中的,那这种类型的数据应该是不定长的。那如何在stack中对这种不定长的数据进行处理呢?
      

  8.   

    stack,heap这些东西只有在优化自己的代码的时候才会考虑到,现在做个程序时间太紧,
    没时间考虑呀,头痛中!
      

  9.   

    本文中有很多结论的推理不严密,比如“前面提到对象实例以及动态属性都是保存在heap中的,而heap必须通过stack中的地址指针才能够被指令(类的方法)访问到。因此可以推断出:静态属性是保存在stack中的” 
    疑点:为什么实例属性保存在heap中就可以推出类属性是保存在stack中的?姑且不讨论文中的用语和结论,先接分,有空再仔细研究研究。
      

  10.   

    好文,解决了我一直想知道的问题。
    谢谢!!
    UP UP UP11
      

  11.   

    Hi, 大家好,我就是本文的作者robbin,真要彻底明确无误搞清楚静态方法和静态属性的问题,就必须去读JVM的C++源代码才能够说自己的结论是正确的,舍此别无它法。不过我不会C++,所以也没有达到那种境界,只是根据自己的 计算机指令系统和CPU原理的知识,结合Java的实际经验进行反向推测,所以也许会有不准确,甚至错误的地方。如果大家有兴趣和我探讨这个问题,可以到我开的Hibernate中文论坛来http://hibernate.fankai.com/在“Java技术”版面发贴,这里我很少来,看不到大家的精辟见解。
      

  12.   

    静态属性如果是基本类型,或者是这样的样子:static String str = "Hello World";在声明的同时就赋值,那么是存放在类的常量池中的,也就是存放在内存指令区,如果是static String str ;....str = "Hello World";那么静态属性的地址指针存放在内存指令区(stack),而内容放在heap中,地址指针是一个4字节的定长数据结构。
      

  13.   

    >> 类的静态方法在 classLoader是 push stack,那么在什么时候弹出 stack方法是指令代码段,只要load进而JVM内存,就不会再释放。指令执行的时候有一个程序计数器,按照一定的顺序读程序,所谓pop stack,只是不在PC指示的代码段中而已。
      

  14.   

    指令放在栈中? 头脑秀逗了...
    栈是用来存放调用method时保护现场的数据的地方!
    在方法里的 new 出来的refrence 和 int xxx = xxxx 的xxx所在空间也是放在那里的.
      

  15.   

    作java程序千万别首先考虑什么堆啊栈啊的,那是JVM的事情,你需要的保证你的代码没有作无用的浪费,再就是选择一个JVM或者调整JVM的参数。
      

  16.   

    作java程序千万别首先考虑什么堆啊栈啊的,那是JVM的事情,
    你需要的是保证你的代码没有作无用的浪费,再就是选择一个
    合适的JVM或者调整JVM的参数。
      

  17.   

    调用类的静态方法,有一条JVM指令,
    invokestatic,将静态方法的参数压栈,然后调用执行该指令就可以了,返回值放到栈顶。
      

  18.   

    to wolfsquare:我前面已经说过了 微机原理 堆栈的 意思
    其实实际要远比我说的复杂,至少我知道堆是很复杂的,有什么全局堆等等JVM 的实现 我没有研究过,也没有看过具体不知道他是怎么实现的你的栈的意思也是从 微机原理 得来的吧那按照你的意思,因该说 这个名称可能不太对
      

  19.   

    静态的东西要是放在最低层话,突然有一个方法要访问它,那么还要将它上面的全部弹出来,放到另外一个???的地方,取出来后,再把???的数据放压回原来的栈.我只能faint了...
      

  20.   

    to wolfsquare:你还是没有明白我的意思我是说 因该 robbin 说的 意思 是和你一样的
    是说栈指令区,而不是单说栈,你明白我的意思吗?不过这是我的理解,也许不一定正确
      

  21.   

    所谓静态方法和域又称为类方法或类变量,而一般方法和和域称为对象方法和对象变量。这就明显了,在语义上可以这样理解,一个对象obj的静态方法和域实际上是该obj对象对应的类obj.class的对象方法,obj.class是一个Class对象,在JVM中只有一个实例,由ClassLoader用时加载。也是用这种方法保证singleton模式的。
    obj1和obj2是同一个类的对象,则obj1.getClass()==obj2.getClass()
    另外在对synchronized对静态方法同步的时候,其实其对象锁就应该是Class对象,而不是Object。
      

  22.   

    JVM规格书中没有规定对象和数组在JVM的内存内是如何呈现的,只提到所有的对象都要通过reference来寻址.具体可以看看.
    另外可以看看这个 :
    Each Java virtual machine thread has a private Java virtual machine stack, created at the same time as the thread. A Java virtual machine stack stores frames . A Java virtual machine stack is analogous to the stack of a conventional language such as C it holds local variables and partial results, and plays a part in method invocation and return. Because the Java virtual machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java virtual machine stack does not need to be contiguous. 
    frame的定义:
    A frame is used to store data and partial results, as well as to perform dynamic linking , return values for methods, and dispatch exceptions. 
    A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception). Frames are allocated from the Java virtual machine stack of the thread creating the frame. Each frame has its own array of local variables , its own operand stack , and a reference to the runtime constant pool  of the class of the current method. 至于 "静态属性保存在stack指令内存区,动态属性保存在heap数据内存区" 的问题,建议尽量使用
    公认的名词来交流.不知道看到这里楼主明白了没有.
      

  23.   

    漏打了一段: 虚拟机的规格具体可以参考
    http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html
      

  24.   

    为了避免误导,还是由我来总结一下:
    1.非静态方法和静态方法的不同:非静态方法有一个隐含的传入参数,该参数是JVM给它的类实例,
    静态方法也有一个隐含的传入参数,该参数是该类的Class对象的引用,这里有点难理解,需要弄明白Class A 和 A.class这两个概念的不一样.
    2.静态属性和动态属性:
      正式的说法是静态成员变量和动态成员变量,从以下可以看出静态成员变量和动态成员变量都是存放在堆中的.
    The Java virtual machine has a heap that is shared among all Java virtual machine threads. The heap is the runtime data area from which memory for all class instances and arrays is allocated. 
      

  25.   

    完全版
    JVM定义了控制Java代码解释执行和具体实现的五种规格,它们是: 
      JVM指令系统 
      JVM寄存器 
      JVM栈结构 
      JVM碎片回收堆 
      JVM存储区 
      2.1JVM指令系统    JVM指令系统同其他计算机的指令系统极其相似。Java指令也是由 操作码和操作数两部分组成。操作码为8位二进制数,操作数进紧随在操作码的后面,其长度根据需要而不同。操作码用于指定一条指令操作的性质(在这里我们采用汇编符号的形式进行说明),如iload表示从存储器中装入一个整数,anewarray表示为一个新数组分配空间,iand表示两个整数的"与",ret用于流程控制,表示从对某一方法的调用中返回。当长度大于8位时,操作数被分为两个以上字节存放。JVM采用了"big endian"的编码方式来处理这种情况,即高位bits存放在低字节中。这同 Motorola及其他的RISC CPU采用的编码方式是一致的,而与Intel采用的"little endian "的编码方式即低位bits存放在低位字节的方法不同。 
      
      Java指令系统是以Java语言的实现为目的设计的,其中包含了用于调用方法和监视多先程系统的指令。Java的8位操作码的长度使得JVM最多有256种指令,目前已使用了160多种操作码。 
      
      2.2JVM指令系统 
    所有的CPU均包含用于保存系统状态和处理器所需信息的寄存器组。如果虚拟机定义较多的寄存器,便可以从中得到更多的信息而不必对栈或内存进行访问,这有利于提高运行速度。然而,如果虚拟机中的寄存器比实际CPU的寄存器多,在实现虚拟机时就会占用处理器大量的时间来用常规存储器模拟寄存器,这反而会降低虚拟机的效率。针对这种情况,JVM只设置了4个最为常用的寄存器。它们是: 
      pc程序计数器 
      optop操作数栈顶指针 
      frame当前执行环境指针 
      vars指向当前执行环境中第一个局部变量的指针 
    所有寄存器均为32位。pc用于记录程序的执行。optop,frame和vars用于记录指向Java栈区的指针。 
      
      2.3JVM栈结构 
      作为基于栈结构的计算机,Java栈是JVM存储信息的主要方法。当JVM得到一个Java字节码应用程序后,便为该代码中一个类的每一个方法创建一个栈框架,以保存该方法的状态信息。每个栈框架包括以下三类信息: 
      局部变量 
      执行环境 
      操作数栈  
      
      局部变量用于存储一个类的方法中所用到的局部变量。vars寄存器指向该变量表中的第一个局部变量。 
      执行环境用于保存解释器对Java字节码进行解释过程中所需的信息。它们是:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。执行环境是一个执行一个方法的控制中心。例如:如果解释器要执行iadd(整数加法),首先要从frame寄存器中找到当前执行环境,而后便从执行环境中找到操作数栈,从栈顶弹出两个整数进行加法运算,最后将结果压入栈顶。 
    操作数栈用于存储运算所需操作数及运算的结果。 
      
      2.4JVM碎片回收堆 
      Java类的实例所需的存储空间是在堆上分配的。解释器具体承担为类实例分配空间的工作。解释器在为一个实例分配完存储空间后,便开始记录对该实例所占用的内存区域的使用。一旦对象使用完毕,便将其回收到堆中。 
    在Java语言中,除了new语句外没有其他方法为一对象申请和释放内存。对内存进行释放和回收的工作是由Java运行系统承担的。这允许Java运行系统的设计者自己决定碎片回收的方法。在SUN公司开发的Java解释器和Hot Java环境中,碎片回收用后台线程的方式来执行。这不但为运行系统提供了良好的性能,而且使程序设计人员摆脱了自己控制内存使用的风险。 
      
      2.5JVM存储区 
    JVM有两类存储区:常量缓冲池和方法区。常量缓冲池用于存储类名称、方法和字段名称以及串常量。方法区则用于存储Java方法的字节码。对于这两种存储区域具体实现方式在JVM规格中没有明确规定。这使得Java应用程序的存储布局必须在运行过程中确定,依赖于具体平台的实现方式。
      

  26.   

    这个贴子理解我认为是完全错误的,具体的实现并不是这个样子的
    大家可以看一下这些资料
    http://www.artima.com/java/index.html
    http://joeq.sourceforge.net/纯java写的一虚拟机,可以参考一下它的实现。
    基本思想应该是一样的