如题

解决方案 »

  1.   

    你不停的分配ByteBuffer,然后改大小,虽然到一定的时候回收机制会回收的,达到个平衡,但是大了就会内存益处
    ByteBuffer.allocate(25*1024*1024);改到JVM的最大内存就可以了
      

  2.   

    xuyang821225(CSDN账号) :
    兄弟,看清楚题目,不是HEAP,是STACK
      

  3.   

    楼主好开心啊~
    Java的基本数据类型存放在JVM的栈空间中
    只要存在了
    如果再次出现就不会继续创建新的对象
    直接指向即可
    那么JVM栈空间的大小和你所使用的数据的多少有关了
    当然重复的不算
    其中float, boolean,byte, short, int, char占用4个byte的空间
    long,double占用8byte空间
      

  4.   

    dreamover(梦醒了):
    说详细点啊JavaHurricane(Java飓风):
    今天是我生日,呵呵
    你的说法中有几个错误:
    (1)Java的基本数据类型存放在JVM的栈空间中 - 错!
    (2)如果再次出现就不会继续创建新的对象,直接指向即可 - 大错!
    (3)JVM栈空间的大小和你所使用的数据的多少有关了 - 特错!
    (4)float, boolean,byte, short, int, char占用4个byte的空间 - 错了2/3
      

  5.   

    反汇编查看一下不就知道了?
    .limit stack 
    .limit locals  
      

  6.   

    很容易啊.用差分法:
    static void function()
    {
        int a = 0;
        System.out.printf(i++);    //i是静态变量
        function();
    }
    先上面的代码,后下面的代码,比较三个个i值.你就大概可以确定一个函数栈除了i以外,其他部分的大小了.然后就可以估计整个栈的大小了.
    static void function()
    {
        int a = 0;
        int b = 0;
        System.out.printf(i++);
        function();
    }static void function()
    {
        int a = 0;
        int b = 0;
        int c = 0;
        System.out.printf(i++);
        function();
    }得到了三个i值,我们分别称为 i1, i2, i3(i3是用来验证的)
    特别是当i(n)数列带入下列方程有解的时候.i1 * (x + 4) == i2 * ( x + 8) == i3 * (x + 12)
    x是我们求一个栈其他空间大小的,因为Java的栈和C的栈的构造可能存在一定的冗余.OK.试验吧.
      

  7.   

    我再加一些解释,如果上面的代码是C++的话,
    栈除了要push ebp等寄存器的值以外,就是栈上变量的空间了.
    但是很少有资料显式java栈要push什么量,我们就用这样的方式来计算.
    当你的栈耗尽的时候,你就得到了i值了.
      

  8.   

    做个递归让它“递归到死”倒是不难,比如下面的程序,我的机器是打印到 12474 然后死掉。但是有两个问题:1. 递归一次消耗的栈空间究竟是多少?2. 在 JVM 中,不会只有一个 STACK 吧?应该是每个线程有一个自己的 STACK 吧?还是别的什么形式?附程序如下:
    package test;
    public class Test27 {
        public static void main(String[] args) {
            go2die(0);
        }
        public static void go2die(int level) {
            System.out.println(level);
            go2die(level + 1);
        }
    }
      

  9.   

    healer_kx(甘草(DotNeting)) :
    不错!交个朋友,QQ154863618
      

  10.   

    正如maquan('ma:kju) 所说healer_kx(甘草(DotNeting))的程序还有些问题,如递归一次消耗的栈空间究竟是多少?因为不只是局部变量会被压入栈中,对函数的引用应该也会被压入栈中,虚拟机倒底怎么管理栈也不清楚
      

  11.   

    dreamover(梦醒了) :
    我题目说的是“估算”,因此,重要的不是答案,是有方法。
    healer_kx(甘草(DotNeting))的方法不算完美,但毕竟已经很接近真相了。
      

  12.   

    to dreamover(梦醒了) .
    我觉得如果JVM的栈和C++的栈的结构如果相似的话,那么我的方式的精度在100字节之内吧?我觉得你没有看我的方程.
      

  13.   

    hbwhwang(我是catmiw的马甲) ( ) 信誉:100  2006-08-07 12:04:00  得分: 0  
     
     
       dreamover(梦醒了):
    说详细点啊JavaHurricane(Java飓风):
    今天是我生日,呵呵
    你的说法中有几个错误:
    (1)Java的基本数据类型存放在JVM的栈空间中 - 错!
    (2)如果再次出现就不会继续创建新的对象,直接指向即可 - 大错!
    (3)JVM栈空间的大小和你所使用的数据的多少有关了 - 特错!
    (4)float, boolean,byte, short, int, char占用4个byte的空间 - 错了2/3  
     
    我怀疑hbwhwang(我是catmiw的马甲)的水平
      

  14.   

    to healer_kx(甘草(DotNeting))不好意思,刚才确实没去想你后面的那个方程
      

  15.   

    JavaHurricane(Java飓风):
    怕了你了,给你指出错误吧。1、基本数据类型是在内存中直接放的值。比如
    int i=100;
    int j=0;
    那么内存中肯定有8个字节,其中4字节放的是100,另4字节放的是0。
    不是你说的什么“指向”,按你的说法,除了上面的8字节外,还有内存来指向100和0,这是错误的!
    比如下面的代码:
    int i=0;
    i=1;
    i=2;
    其实改的都是同一内存地址的内容。2、基本数据类型,如果是数据成员,毫无疑问是放在堆中的。如果是临时变量,则放在栈中。3、JVM栈的大小是定数,是你开JVM的时候就已经决定了的,跟你的数据无关。4、boolean和byte占1字节,short和char占2字节。不信的话,你把这些类型的数据写到硬盘上看文件大小啊。
      

  16.   

    (1)Java的基本数据类型存放在JVM的栈空间中 
       所有的局部变量,形式参数都是从栈中分配内存空间的
    (2)如果再次出现就不会继续创建新的对象,直接指向即可
       你说的是栈,不是堆~
    (3)JVM栈空间的大小和你所使用的数据的多少有关了 !
       意思是你要求JVM的空间,从局部变量占用的空间就可以求出
      

  17.   

    JavaHurricane(Java飓风) :
    问你一个问题:
    class A{
        int i=0;
    }public class B{
        public static void main(String[] args){
             A a=new A();
        }
    }
    这段代码运行的时候,那个0是放在堆还是栈中?i呢?a呢?public class B{
        public static void main(String[] args){
             int[][] arr=new [5][10];
        }
    }
    这段代码运行的时候,arr在堆还是栈?a[1]在堆还是栈?a[1][1]在对还是栈?
      

  18.   

    再问你一个问题:
    int[][] a=new int[5][10];

    int[][] a=new int[10][5];
    有什么区别?
    如果你就是为了用a来存储一个10*5的矩阵,你会用前面还是后面的?为什么?
      

  19.   

    栈有一个很重要的特殊性
    就是存在栈中的数据可以共享
    假设同时定义:
    int a = 0; 
    int b = 0; 
    编译器先处理int a = 0;
    首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为0的地址,没找到,就开辟一个存放0这个字面值的地址,然后将a指向0的地址。
    接着处理int b = 3;
    在创建完b的引用变量后,由于在栈中已经有0这个字面值,便将b直接指向0的地址。这样,就出现了a与b同时均指向0的情况。所以healer_kx(甘草(DotNeting)) 的方法也是错误的
      

  20.   

    JavaHurricane(Java飓风) :
    其实你最大的错误不是在第4点。而是在你没有明白代码中:
    int a=0;
    int b=0;
    编译器看到第一句,它就划出4字节来表示a,然后把4字节写成0
    看到第二句,它就划出4字节来表示b,然后也把4字节写成0!而不是你说的什么“字面量”做法!
    我看到过一篇文章跟你的说法很象,不知道是不是你写的,如果是你写的,那你真是误人子弟!
      

  21.   

    JVM的栈有三个区域:局部变量区、运行环境区、操作数区
    每个Java方法使用一个固定大小的局部变量集
    它们按照与vars寄存器的字偏移量来寻址
    局部变量都是32位的
    只有长整数和双精度浮点数占据了两个局部变量的空间所以上面我说的第四个也是正确的,你又错了
    例如
    一个具有索引n的局部变量,如果是一个双精度浮点数,那么它实际占据了索引n和n+1所代表的存储空间
    虚拟机规范并不要求在局部变量中的64位的值是64位对齐的。虚拟机提供了把局部变量中的值装载到操作数栈的指令,也提供了把操作数栈中的值写入局部变量的指令
      

  22.   

    JavaHurricane(Java飓风) :
    我想请教你一个问题:
    int i=0;
    i++;
    JVM怎么实现的?
      

  23.   

    你再帮我解释一下:for (int i=0;i<100000000;i++){
    }
    运行完了之后,栈里面到底有多少个整数?
      

  24.   

    平时做的时候只知道用,没具体去考虑哪个放在堆中,哪个放在栈中的,也许这就是高手与菜鸟的区别吧-_-! hbwhwang(我是catmiw的马甲) 提的那几个问题给我们具体讲讲吧,真的还有点兴趣知道答案哦,估计也有很多人和我一样吧,呵呵。
      

  25.   

    顶···顺便再次深入学习一下····int i=0;
    i++;
    JVM怎么实现的?(位置不变,然后把0改成1,是么?)for (int i=0;i<100000000;i++){
    }
    运行完了之后,栈里面到底有多少个整数?(里面有么?)请教··
      

  26.   

    JavaHurricane(Java飓风)对栈完全没有一个正确的认识!建议你先到C++版看看我的级别再发话.你也顺便学学C和C++.
      

  27.   

    表Mark了,到我的blog看D语言吧...
      

  28.   

    sixme(子曾经曰过:“算法是王道”。) ( ) 信誉:100  2006-8-7 18:27:12  得分: 0 
    顶···顺便再次深入学习一下····int i=0;
    i++;
    JVM怎么实现的?(位置不变,然后把0改成1,是么?)for (int i=0;i<100000000;i++){
    }
    运行完了之后,栈里面到底有多少个整数?(里面有么?)请教··-------------------------------------------
    如果不考虑寄存器做临时变量的话,是有的。
    因为实际上是寄存器里面的INC,所以没有了,但并不表示
    理论算法上没有,javap 就知道了,有一个push,和pop
      

  29.   

    马甲老师前面出了几道题,一直没给答案。我这里试着回答一下,不对的地方,请马甲老师指正  :)> class A{
    >     int i=0;
    > }
    >
    > public class B{
    >     public static void main(String[] args){
    >          A a=new A();
    >     }
    > }
    > 这段代码运行的时候,那个0是放在堆还是栈中?i呢?a呢?    new A() 应该是在堆中分配了一个对象。
        a 是一个引用型的变量,因为是局部变量,它本身是在栈中,其值指向上面分配的那个对象。
        i 因为是那个对象的成员,所以也在堆中。
        0 根本不存在,因为它是由一个 iconst_<i> 指令体现的。如果这个值不是 (-1, 0, 1, 2, 3, 4, 5) 中的一个,而是其它的值,那它是个“立即操作数”,应该在“代码段”,既不在堆中,也不在栈中。> public class B{
    >     public static void main(String[] args){
    >          int[][] arr=new [5][10];
    >     }
    > }
    > 这段代码运行的时候,arr在堆还是栈?a[1]在堆还是栈?a[1][1]在对还是栈?    arr 是一个引用型的变量,因为是局部变量,它本身是在栈中,其值指向堆中的一个对象。
        堆中的那个类型为 int[][] 的“二维数组对象”细说起来是有内部结构的(并不像 C 程序那样只是一块 5×10 的连续的内存空间),处在第一层的是一个一维数组对象,有 5 个元素,每个元素都是一个引用型的变量,其值指向堆中的一个类型为 int[] 的“一维数组对象”,这些“一维数组对象”就是第二层,每个数组包含 10 个元素,每个元素都是一个 int 型的变量,其值被初始化为 0。
        a[1] 是堆中的一个 int[] 型的变量。
        a[1][1] 是堆中的一个 int 型的变量。> int[][] a=new int[5][10];
    > 和
    > int[][] a=new int[10][5];
    > 有什么区别?
    > 如果你就是为了用a来存储一个10*5的矩阵,你会用前面还是后面的?为什么?    int[5][10] 在堆中共有 5 个“int[] 引用型变量”、5 个“int[10] 对象”,
        int[10][5] 在堆中共有 10 个“int[] 引用型变量”、10 个“int[5] 对象”,
        假定一个引用型变量占据的字节数是 m,一个 int 型变量占据的字节数是 n,一个数组对象的额外开销字节数是 p,那么
        int[5][10] 在堆中占据的字节数是 5*m+p + 5*(10*n+p) = 5*m + 50*n + 6*p
        int[10][5] 在堆中占据的字节数是 10*m+p + 10*(5*n+p) = 10*m + 50*n + 11*p
        虽然 m、n、p 的值我还不知道,但可以肯定 int[10][5] 比 int[5][10] 所需要的内存开销会大一些。
        所以,如果只考虑内存因素的话,应该让靠前的维度的下标尽可能小。> int i=0;
    > i++;
    > JVM怎么实现的?    javap 的结果如下。    public static void main(java.lang.String[]);
          Code:
           Stack=1, Locals=2, Args_size=1
           0: iconst_0            // 在栈顶 push 一个整数 0 值
           1: istore_1            // 把栈顶的一个整数值存到 Slot1 的局部变量里(那个就是 i)
           2: iinc 1, 1        // 把 Slot1 那个局部变量值进行“加1”操作
           5: return
          LocalVariableTable: 
           Start  Length  Slot  Name   Signature
           0      6      0    args       [Ljava/lang/String;
           2      4      1    i       I> for (int i=0;i<100000000;i++){
    > }
    > 运行完了之后,栈里面到底有多少个整数?    javap 的结果如下,所以,栈顶一直会有一个整数进进出出。如果局部变量 i 也在栈中的话,它应该在稍微下面一点,而且一直在那儿,一直到最后它还在那儿。    public static void main(java.lang.String[]);
          Code:
           Stack=2, Locals=2, Args_size=1
           0: iconst_0
           1: istore_1
           2: goto 8
           5: iinc 1, 1
           8: iload_1
           9: ldc #16; //int 100000000
           11: if_icmplt 5
           14: return
          LocalVariableTable: 
           Start  Length  Slot  Name   Signature
           0      15      0    args       [Ljava/lang/String;
           2      12      1    i       I
      

  30.   

    费了九牛二虎的力气,终于把答卷写完了,都块累残了(还不知道结果对不对……)不过,写到最后两题的时候,我忽然又产生了一个疑问:“局部变量是在栈中”这句话对吗?我原来一直以为是没有问题的,现在想到了一个问题。C 编译器生成的指令当然是这样的(不考虑寄存器变量的情况),但 Java 编译器生成的结果是什么样的呢?用 javap 看到的情况,它有一个 LocalVariableTable,并没有说是在“栈中”啊。JVM 所能识别并执行的指令集中,大部分都跟“栈”有关,那个叫做 operand stack(应该翻译成“操作数栈”吧?),那么,JVM 在 run-time 是怎么实现 LocalVariableTable 的呢?想必应该是个“栈”吧,但问题是它跟那个 operand stack 是同一个栈吗?理论上,可以用两个不同的栈吧?C 程序编译出来的代码是给 CPU 执行的,CPU 只有一套“栈指针寄存器”,所以一个线程只有一个栈,为了区别入口参数、局部变量和指令操作数,要用到 BP、SP 什么的。Java 编译出来的代码是给 JVM 执行的,如果 JVM 愿意,他是不是可以定义多套“栈指针寄存器”来分别管理 operand stack 和 local variable stack 呢?甚或是,JVM 就愿意在“堆”中实现 LocalVariableTable,又怎么样呢?这倒又回到楼主的原题了,楼主不是让我们“估测出JVM栈空间的大小”吗,能不能先给我们讲讲“JVM 里的栈到底是个什么东西”呢?  ^_^
      

  31.   

    maquan('ma:kju):
    首先感谢你替我回答问题,你的答案我仔细看了。以我有限的水平,看不出你答案中不对的地方,先赞你一个--扎实!然后,来谈谈我对JVM的STACK的认识。(如果错了,欢迎拍砖!)1、栈STACK和堆HEAP都是内存。
    2、STACK和HEAP的原理根据JVM的实现者不同而有所区别,但大多数情况下,STATCK就是HEAP里面的一块或者多块。
    3、每个线程有一个STACK,这就是我们常说的“栈”,我让测的就是这个东西的大小。
    4、在同一个线程中的每一次调用,都会有一个称为STACK FRAME(栈桢)的东西入栈(PUSH),这个栈桢里面包含你说的operand stack(操作栈) 和 local variable stack(局部变量栈)。
    5、局部变量栈虽然称为栈,但它的用法一点也不象栈。它里面放的是本次调用(方法)中用到的局部变量。是按出现的代码次序编号的。
    6、
    (1) main() { int i=0; }
    (2) main() { for (int i=0;i<100;i++) }
    二者中的i都放在局部变量栈,但是后者在出了循环之后就废了,可以被重用,这是2者最大的区别。
    7、操作栈的行为象栈,它里面会压进去计算所用的东西,比如调用的参数、计算用的值。
    8、局部变量栈区是以“字WORD”为单位的,除开long,double占2个字,其他的(包括引用)都是1个字。知道的大概就这些了!请指正~
      

  32.   

    能得到老师的首肯,我心甚欢  :)
    我可是一边查资料,一边做实验,一边答题的,真累呀……看了马甲老师的关于 STACK 的精彩讲述,我对一次 method calling 的执行细节有了更清楚、更感性的认识,受益匪浅!如果这样说下去,那么题目中“估测 JVM 栈空间的大小”,应该就是可以准确(或者是基本准确)地得到了。比如我前面写的那个“递归到死”的程序:    public static void go2die(int level) {
            System.out.println(level);
            go2die(level + 1);
        }每次调用由于只增加了一个 int 型局部变量占用的空间,也就是 1 个“字WORD”,那么 12474 次调用,应该是 49896 个字节,如果每个 STACK FRAME 没有额外开销的话,这个应该就是一个应用程序可用的栈空间了。我这么理解对吗?
      

  33.   

    to maquan('ma:kju) :
    你的理解是错的“每次调用由于只增加了一个 int 型局部变量占用的空间”
    你仔细看我上面关于“栈桢”的描述,“在同一个线程中的每一次调用,都会有一个称为STACK FRAME(栈桢)的东西入栈(PUSH),这个栈桢里面包含你说的operand stack(操作栈) 和 local variable stack(局部变量栈)。”
    因此,每次调用不是只增加一个 int 型局部变量,而是很多空间!
      

  34.   

    > class A{
    >     int i=0;
    > }
    >
    > public class B{
    >     public static void main(String[] args){
    >          A a=new A();
    >     }
    > }
    > 这段代码运行的时候,那个0是放在堆还是栈中?i呢?a呢?    new A() 应该是在堆中分配了一个对象。
        a 是一个引用型的变量,因为是局部变量,它本身是在栈中,其值指向上面分配的那个对象。
        i 因为是那个对象的成员,所以也在堆中。
        0 根本不存在,因为它是由一个 iconst_<i> 指令体现的。如果这个值不是 (-1, 0, 1, 2, 3, 4, 5) 中的一个,而是其它的值,那它是个“立即操作数”,应该在“代码段”,既不在堆中,也不在栈中。
    那个0不存在的问题能不能再解释下????
      

  35.   

    > 你的理解是错的“每次调用由于只增加了一个 int 型局部变量占用的空间”
    > 你仔细看我上面关于“栈桢”的描述,“在同一个线程中的每一次调用,都会
    > 有一个称为STACK FRAME(栈桢)的东西入栈(PUSH),这个栈桢里面包含你说的
    > operand stack(操作栈) 和 local variable stack(局部变量栈)。”
    > 因此,每次调用不是只增加一个 int 型局部变量,而是很多空间!多谢马甲老师指正,我那个结论的确是太草率了。我后面进一步做了一些实验,包括用前面甘草兄给出的方法,也意识到这个问题了。我用甘草兄的方法进行实验,三次运行的结果分别是 8816, 7556, 6612那么,用 i1 * (x + 4) == i2 * ( x + 8) == i3 * (x + 12) 解出的结果,x = 19那是不是说栈空间是 8816 * (19 + 4) = 202768 呀?
      

  36.   

    报告一个很奇怪的现象:如果程序是下面的样子,就能执行 8816 次:
        static void go2die(int a)
        {
            System.out.println(i++);    //i是静态变量
            go2die(a+1);
        }而如果程序是下面的样子,就能执行 12474 次:
        static void go2die(int a)
        {
            System.out.println(a);
            go2die(a+1);
        }难道访问了一下静态变量,就会消耗“栈空间”吗?
      

  37.   

    maquan('ma:kju) :
    嗯,你得出的是栈的可用空间的大致数。这跟整个栈的大小基本接近了
      

  38.   

    maquan('ma:kju) :
    你把
        static void go2die(int a)
        {
            System.out.println(i++);    //i是静态变量
            go2die(a+1);
        }
    改成:
        static void go2die(int a)
        {
            i++;
            System.out.println(a);    //i是静态变量
            go2die(a+1);
        }你会发现后面的写法跟
        static void go2die(int a)
        {
            System.out.println(a);    //i是静态变量
            go2die(a+1);
        }
    是一样的。
    由此可见,整个差距是在调用System.out.println,使用static变量与local变量的差别造成的。这种差距在哪里,我也不知道~
      

  39.   

    > 那个0不存在的问题能不能再解释下????    class A{
            int i = 0;
        }把这个 class 用 javap 看一下,能看到:
      Code:
       Stack=2, Locals=1, Args_size=1
       0:   aload_0
       1:   invokespecial   #11; //Method java/lang/Object."<init>":()V
       4:   aload_0
       5:   iconst_0
       6:   putfield        #13; //Field i:I
       9:   return其中 5: 就是把一个常数 0 放入栈顶,而 6: 就是把栈顶的数存到一个成员变量里面去。这里 iconst_0 是一个指令,没有操作数。程序该成下面的样子:
        class A{
            int i = 6;
        }
    再用 javap 看:
      Code:
       Stack=2, Locals=1, Args_size=1
       0:   aload_0
       1:   invokespecial   #11; //Method java/lang/Object."<init>":()V
       4:   aload_0
       5:   bipush  6
       7:   putfield        #13; //Field i:I
       10:  return其中 5: 就是把一个常数 6 放入栈顶,其它一样。这里 bipush 6 是一个指令,带一个操作数。详细信息可以参考:
        《The Java Virtual Machine Specification》
        iconst_<i>: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc6.html
        bipush: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc1.html
      

  40.   

    这个iconst_<i>,是JVM中让人很难以理解的玩意。
    我就想不通它这么做有什么理由~~
      

  41.   

    对于这个方程,我想修正一下了。那么,用 i1 * (x + 4) == i2 * ( x + 8) == i3 * (x + 12) 解出的结果,x = 19我忽略了一点,
    4是int的sizeof,但是 不是一个值变量的大小,一个值变量大小应该是
    4 + 一个常数c
    所以
    第二个函数就是
    8 + c *2;
    第三个个函数就是
    12 + c * 3;所以方程修正为:
    i1 * (x + 4 + c) == i2 * ( x + (4 + c) * 2) == i3 * (x + (4 + c) * 3)现在是2元方程了!:)i1 i2 i3 的值是8816, 7556, 6612 代入。可求得结果。结果会更加精确!
    202768 这个是不准确的,我看到后才产生了怀疑的,不好意思啊,白算一次
    这次应该是可以的。
    我看过kaffe(一种访Java的语言)的源码,一个int a在栈上的空间还有其他的size呢。
      

  42.   

    > 由此可见,整个差距是在调用System.out.println,使用static变量与local变量的差别造成的。
    > 这种差距在哪里,我也不知道~报告老师,我找到一个线索!
        static void go2die_1(int a)
        {
            System.out.println(i++);    //i是静态变量
            go2die_1(a+1);
        }
        static void go2die_2(int a)
        {
            System.out.println(i);    //i是静态变量
            i++;
            go2die_2(a+1);
        }
        static void go2die_3(int a)
        {
            System.out.println(a);
            go2die_3(a+1);
        }其中,go2die_1() 能跑 8816 次,而 go2die_2() 和 go2die_3() 能跑 12474 次。这大概可以说明,并不是“访问静态变量”消耗了额外的栈空间,而是变量 i 作为实参进行了“后自增”计算,而 i 本身又不在当前的栈中,所以就在当前栈中开出一个空间做临时存储。
      

  43.   

    > 这个iconst_<i>,是JVM中让人很难以理解的玩意。
    > 我就想不通它这么做有什么理由~~我想可以节省一点 .class 文件的体积吧。毕竟程序中很多情况都是赋初值为 0。反正那么多值可以用来做 Instruction Code,闲着也是闲着  :D
      

  44.   

    > 所以方程修正为:
    > i1 * (x + 4 + c) == i2 * ( x + (4 + c) * 2) == i3 * (x + (4 + c) * 3)
    > 现在是2元方程了!:)
    > i1 i2 i3 的值是8816, 7556, 6612 代入。甘草兄,你就帮忙给解一下吧。我解方程不灵……
      

  45.   

    偶然发现:maquan('ma:kju) 
    healer_kx(甘草(我很看好你哦~~~)) 
    hbwhwang(我是catmiw的马甲) 此3个爱瞎折腾的ID都是 ▲▲▲▲如果再来个FEMALE,咱也整个GOF出来
      

  46.   

    hbwhwang(我是catmiw的马甲) ( ) 信誉:100  2006-08-11 11:53:00  得分: 0  
     
     
       这个iconst_<i>,是JVM中让人很难以理解的玩意。
    我就想不通它这么做有什么理由~~
      
     
    --------------------------这些操作码是不带操作数的,相对于其他方式,更加有效,由于这些都是冗余指令,所以不能过多,就这么常用的几个。 maquan('ma:kju) ( ) 信誉:100  2006-08-11 11:46:00  得分: 0  
     
     
       > 那个0不存在的问题能不能再解释下????    class A{
            int i = 0;
        }把这个 class 用 javap 看一下,能看到:
      Code:
       Stack=2, Locals=1, Args_size=1
       0:   aload_0
       1:   invokespecial   #11; //Method java/lang/Object."<init>":()V
       4:   aload_0
       5:   iconst_0
       6:   putfield        #13; //Field i:I
       9:   return其中 5: 就是把一个常数 0 放入栈顶,而 6: 就是把栈顶的数存到一个成员变量里面去。这里 iconst_0 是一个指令,没有操作数。程序该成下面的样子:
        class A{
            int i = 6;
        }
    再用 javap 看:
      Code:
       Stack=2, Locals=1, Args_size=1
       0:   aload_0
       1:   invokespecial   #11; //Method java/lang/Object."<init>":()V
       4:   aload_0
       5:   bipush  6
       7:   putfield        #13; //Field i:I
       10:  return其中 5: 就是把一个常数 6 放入栈顶,其它一样。这里 bipush 6 是一个指令,带一个操作数。详细信息可以参考:
        《The Java Virtual Machine Specification》
        iconst_<i>: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc6.html
        bipush: http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc1.html
      
     
    --------------------------
    所谓的这个0不存在,我不知道是理解差异还是别的什么,iconst_0和bipush  6的区别只是怎么得到这个数字并压入操作数栈,再向后的执行就一样了。
      

  47.   

    flyforlove(为情飞):
    0肯定存在撒,不存在的话让计算机怎么做。关键是在哪里,也就是说 iconst_0 是从哪里拖这个0过来的
      

  48.   

    > 所谓的这个0不存在,我不知道是理解差异还是别的什么,iconst_0和bipush  6的区别只是怎么得到这个数字并压入操作数栈,再向后的执行就一样了。我说“0 不存在”的意思是这样的:无论在 .class 文件里,还是在 JVM 的 run-time 的堆里或者栈里,都找不到这个 0 值,因为 iconst_0 是一个没有操作数的指令,在 .class 文件里(或者说在 run-time 的“代码段”里)只是一个字节 0x03,当然这个指令执行完之后,栈顶会有一个 0 值,但这已经不是当初那个“常量 0”了。相比之下,bipush 6 就不同,它是带有一个操作数的指令,在 .class 文件里(或者说在 run-time 的“代码段”里)是 0x10 0x06 两个字节,而这里的 0x06 就是那个“常量 6”,它是存在于“代码段”里的。
      

  49.   

    > 0肯定存在撒,不存在的话让计算机怎么做。关键是在哪里,也就是说 iconst_0 是从哪里拖这个0过来的就 iconst_0 而言,这个“0”是存在于 JVM 的“指令执行逻辑”里的,并不在内存中。也就是说,当 JVM 看到 iconst_0(0x03)这个指令的时候,就在栈顶放一个 0 值。
      

  50.   

    maquan('ma:kju) :
    你要说只有个0,我还觉得可行。但是不光是个0啊,这些数在内存里面肯定存在,不然偷去啊
      

  51.   

    iconst_0是不存在于class中,这个指令是对0专用的,所以不需要把它放到字节码流里,但是它是存在于内存里的,java的栈有三个区:局部变量区、运行环境区、操作数区。对于一个赋值语句的话,有三种情况,其中只有把数据压入操作数区时会有不同
    1种是根据指令直接压栈,就像是刚才的iconst_0
    1种是从字节码流中读取数值,然后压栈,就像bipush  6
    1种是从常量池去值,然后压栈,这个操作码为<ldc 常量池入口>等等压入操作数区以后,就要从操作数区弹出,然后保存到局部变量区。所以说这个0是存在于局部变量区的。对于下面这个语句
      int i=0;
      int j=i;
    其编译后代码为
       0:   iconst_0
       1:   istore_1
       2:   iload_1
       3:   istore_2
       4:   return其中2:这条语句,是从局部变量区位置1取数压入操作数区,在从操作数区探出存到局部变量区2的位置。如果说0这个东西不存在的话,这个过程是没有办法完成的。
      

  52.   

    修改下第一句话,“iconst_0是不存在于class中”,我的意思是编译成class文件时,由于这儿是0(其实1-5都一样),所以就没有把它放到字节码流里,当然也就不存在于class文件里了。
      

  53.   

    OK,我来接方程了。==> x = 20 + 5c;
    这个是有两个方程推出的x和c的关心。我突然觉得很振奋。!当然了,你看着毕竟玄,觉得猜测的成分比较大。
    但是我前面的一次说明,和后来的修正, 和将要得出的结果,可以说明问题了。
      

  54.   

    > iconst_0是不存在于class中,这个指令是对0专用的,所以不需要把它放到
    > 字节码流里,但是它是存在于内存里的我再强调一下吧。我说的“0 根本就不存在”是说 int i=0; 里面那个“常数值 0”是根本就不存在的,它只存在于 JVM 的“指令执行逻辑”中。而在运行的过程中,当然会出现一个 0 值,先是在栈顶短暂出现了一下,随后就是在变量 i 那个位置出现。作为对比,如果是 int i=6; 那么,这个“常数值 6”就是在内存中真实存在的,因为 bipush 6 这个指令由两个字节组成(0x10 0x06),这里的 0x06 就是存在于“代码段”的那个“常数值 6”,随后会有一个 6 在栈顶短暂出现一下,再然后就是变量 i 那个位置的值变成了 6。
      

  55.   

    看来是个人理解不一样,我觉得讨论这个也没有什么意义了。源代码的意义是由编译器来决定的,int i=0;int i=6;之所以出现的结果不一样,也是因为编译器在解析时按照spec这样做的。常数“0”存在不存在不重要,只要0的意义存在就可以了。因为即使即时在源代码里有0这个常数值,编译器也可以把它解析成别的什么,关键是0的意义存在不存在。
      

  56.   

    好一场血雨腥风~~虽然maquan('ma:kju) 你对了很多,但是这次我和flyforlove(为情飞)占在一起的。不过正如flyforlove(为情飞)所言,讨论这个没有什么意义。你难道没有看到:分不清堆栈的人照样混饭吃呵呵~~
      

  57.   

    hehe, 严重同意飞兄最后的观点,至于这个“0”物理上是否存在并不重要,只要它的逻辑意义清楚就够了。我也只是感觉前面可能没太说清楚,有些文字上的误会,所以才又强调了一次。综观这场“血雨腥风”,其实,我真的觉得,这里得出的每个结论其实都不重要,对我来说,更重要的是看到了、经历了很多解决问题的思路和研究方法。马甲老师关于栈的工作细节的描述,固然是让人眼前一亮。而甘草兄最早给出的差分分析法,更是在最少信息的前提下,用“方法”解决问题的经典!佩服!学习!共勉!
      

  58.   

    maquan('ma:kju) :
    你的严谨治学态度,也让我敬佩不已啊!好了,结帖了!
    希望我的下一个帖子大家也来捧场!不甚荣幸之至~