锁定老帖子 主题:代码难道不是这么写的?
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-07-30
coffeesweet 写道 来看s 的
把java的for ... in...的源码看一下就明白了 能在详细解释下么,对待新人要耐心一些么, 我还是不知道s 干吗的? |
|
返回顶楼 | |
发表时间:2010-07-30
那你可以写个小程序测试一下,比如说设置-Xms32m -Xmx32m,然后用两个方法往里放一些大的字符串,结果应该是基本相同的。
你们的评审人员说的应该是有问题的,但是你要注意他有可能也在看这个帖子,呵呵。 |
|
返回顶楼 | |
发表时间:2010-07-30
fengfeng925 写道 qiushily2030 写道 A a;
申明在内部,每次遍历都申明一个a的变量. 申明在外面 只申明一次 一直复用. 申明也是要资源的.. 一个变量就相当于一个指针,循环1亿次,LZ你说呢. 评审官说的还是有理的,不过这个得看需求. JVM回收是在内存不足的时候. 还是不要想当然了,我就那么干过一回. 程序是最真实的答案... 简直是TMD胡扯。 JVM回收是在内存不足的时候.这个已经修正. 不是内存不足才调用。。 你说我胡扯? 那for里定义的局部变量放哪里?不要也和上面一个的观点一样:只申明一次,后调用索引. 这个我不可理解。。 |
|
返回顶楼 | |
发表时间:2010-07-30
FreeWhere 写道 其实重点是在垃圾回收这里
看到了一些错误知识 误导了我. 垃圾回收机制还是去看 深入java虚拟机 |
|
返回顶楼 | |
发表时间:2010-07-30
qiushily2030 写道 fengfeng925 写道 qiushily2030 写道 A a;
申明在内部,每次遍历都申明一个a的变量. 申明在外面 只申明一次 一直复用. 申明也是要资源的.. 一个变量就相当于一个指针,循环1亿次,LZ你说呢. 评审官说的还是有理的,不过这个得看需求. JVM回收是在内存不足的时候. 还是不要想当然了,我就那么干过一回. 程序是最真实的答案... 简直是TMD胡扯。 JVM回收是在内存不足的时候.这个已经修正. 不是内存不足才调用。。 你说我胡扯? 那for里定义的局部变量放哪里?不要也和上面一个的观点一样:只申明一次,后调用索引. 这个我不可理解。。 恩,说你胡扯是我不对。 放在for循环里,每循环一次,声明一个局部变量,一次循环结束,局部变量消失。进入第二次循环。再声明一个变量,消失的那个变量内存已经回来了,不是说重复声明多个a变量。 |
|
返回顶楼 | |
发表时间:2010-07-30
qiushily2030 写道 fengfeng925 写道 qiushily2030 写道 A a;
申明在内部,每次遍历都申明一个a的变量. 申明在外面 只申明一次 一直复用. 申明也是要资源的.. 一个变量就相当于一个指针,循环1亿次,LZ你说呢. 评审官说的还是有理的,不过这个得看需求. JVM回收是在内存不足的时候. 还是不要想当然了,我就那么干过一回. 程序是最真实的答案... 简直是TMD胡扯。 JVM回收是在内存不足的时候.这个已经修正. 不是内存不足才调用。。 你说我胡扯? 那for里定义的局部变量放哪里?不要也和上面一个的观点一样:只申明一次,后调用索引. 这个我不可理解。。 主要你误解了a变量在遍历中,有入栈和出栈的操作。并没有重复开辟局部变量,再说JVM优化之后,不会重复创建。 |
|
返回顶楼 | |
发表时间:2010-07-30
kongxx 写道 那你可以写个小程序测试一下,比如说设置-Xms32m -Xmx32m,然后用两个方法往里放一些大的字符串,结果应该是基本相同的。
你们的评审人员说的应该是有问题的,但是你要注意他有可能也在看这个帖子,呵呵。 设置Heap的参数没有一点意义,倒是可以设置-Xss线程的栈空间大小来试试。 |
|
返回顶楼 | |
发表时间:2010-07-30
qiushily2030 写道 fengfeng925 写道 qiushily2030 写道 A a;
申明在内部,每次遍历都申明一个a的变量. 申明在外面 只申明一次 一直复用. 申明也是要资源的.. 一个变量就相当于一个指针,循环1亿次,LZ你说呢. 评审官说的还是有理的,不过这个得看需求. JVM回收是在内存不足的时候. 还是不要想当然了,我就那么干过一回. 程序是最真实的答案... 简直是TMD胡扯。 JVM回收是在内存不足的时候.这个已经修正. 不是内存不足才调用。。 你说我胡扯? 那for里定义的局部变量放哪里?不要也和上面一个的观点一样:只申明一次,后调用索引. 这个我不可理解。。 不可理解就看看字节码,了解下java的方法调用是怎么回事儿,这不就理解了。 |
|
返回顶楼 | |
发表时间:2010-07-30
qiushily2030 写道 fengfeng925 写道 qiushily2030 写道 A a;
申明在内部,每次遍历都申明一个a的变量. 申明在外面 只申明一次 一直复用. 申明也是要资源的.. 一个变量就相当于一个指针,循环1亿次,LZ你说呢. 评审官说的还是有理的,不过这个得看需求. JVM回收是在内存不足的时候. 还是不要想当然了,我就那么干过一回. 程序是最真实的答案... 简直是TMD胡扯。 JVM回收是在内存不足的时候.这个已经修正. 不是内存不足才调用。。 你说我胡扯? 那for里定义的局部变量放哪里?不要也和上面一个的观点一样:只申明一次,后调用索引. 这个我不可理解。。 方法的参数连同方法里的变量所占用的空间,在编译时就已经确定了,它决定了运行时一个方法被调用的时侯要分配多大的栈帧。一个变量放在循环外还是循环里,只是在编译期限定了其作用域而已,到了运行时是没有区别的(也许只是在栈帧的local variables区里的位置不同)。 看一下方法的字节码,一切都非常明了: private final int[] numbers = {1, 2, 3, 4, 5}; public void varOutsideLoop() { int n; for (int i = 0; i < numbers.length; i++) { n = numbers[i]; System.out.println(n); } } public void varInsideLoop() { for (int i = 0; i < numbers.length; i++) { int n = numbers[i]; System.out.println(n); } } 对应的字节码: public void varOutsideLoop(); Signature: ()V Code: Stack=2, Locals=3, Args_size=1 0: iconst_0 1: istore_2 2: goto 22 5: aload_0 6: getfield #12; //Field numbers:[I 9: iload_2 10: iaload 11: istore_1 12: getstatic #19; //Field java/lang/System.out:Ljava/io/PrintStream; 15: iload_1 16: invokevirtual #25; //Method java/io/PrintStream.println:(I)V 19: iinc 2, 1 22: iload_2 23: aload_0 24: getfield #12; //Field numbers:[I 27: arraylength 28: if_icmplt 5 31: return LineNumberTable: line 43: 0 line 44: 5 line 45: 12 line 43: 19 line 47: 31 LocalVariableTable: Start Length Slot Name Signature 0 32 0 this Lcom/jstudio/learnjvm/classloader/VarInLoop; 12 10 1 n I 2 29 2 i I public void varInsideLoop(); Signature: ()V Code: Stack=2, Locals=3, Args_size=1 0: iconst_0 1: istore_1 2: goto 22 5: aload_0 6: getfield #12; //Field numbers:[I 9: iload_1 10: iaload 11: istore_2 12: getstatic #19; //Field java/lang/System.out:Ljava/io/PrintStream; 15: iload_2 16: invokevirtual #25; //Method java/io/PrintStream.println:(I)V 19: iinc 1, 1 22: iload_1 23: aload_0 24: getfield #12; //Field numbers:[I 27: arraylength 28: if_icmplt 5 31: return LineNumberTable: line 50: 0 line 51: 5 line 52: 12 line 50: 19 line 54: 31 LocalVariableTable: Start Length Slot Name Signature 0 32 0 this Lcom/jstudio/learnjvm/classloader/VarInLoop; 2 29 1 i I 12 7 2 n I 仔细看字节码就能发现,除了n和循环变量i在local variable table中的位置不同,其他的所有的都没有区别。 varOutsideLoop那个方法里我故意没有初始化n,如果加上初始化,就会多一条iconst和一条istore指令。 至于位置不一样的原因,个人猜测与变量出现的位置有关,n在循环外的版本,它出现在前,所以占据了第一个slot(第0个slot是对象本身,即this);n在循环里的版本,循环变量i出现在前,所以i占据了第一个slot,而n占用的是第二个slot。 除此之外,两个方法没有任何的区别。 mercyblitz 写道 主要你误解了a变量在遍历中,有入栈和出栈的操作。并没有重复开辟局部变量,再说JVM优化之后,不会重复创建。 个人认为这种说法也不太对,在一个方法内部不会有所谓的“入栈”和“出栈”操作。方法里,一个变量占用一个local variable table的slot,一个萝卜一个坑。所有这些变量都是在方法结束,堆栈帧被销毁的时侯才真正被“回收”,即使方法结束的时侯它早以超出了自己的作用域…… 实践中,变量的作用域当然是尽可能小才好,即有利于垃圾收集、也消除了一些潜在的导致bug的隐患。 楼主别理那个“代码评审官”就好……话说如果我遇到这种人这种事,我八成不愿继续干下去…… |
|
返回顶楼 | |
发表时间:2010-07-30
moonranger 写道 qiushily2030 写道 fengfeng925 写道 qiushily2030 写道 A a;
申明在内部,每次遍历都申明一个a的变量. 申明在外面 只申明一次 一直复用. 申明也是要资源的.. 一个变量就相当于一个指针,循环1亿次,LZ你说呢. 评审官说的还是有理的,不过这个得看需求. JVM回收是在内存不足的时候. 还是不要想当然了,我就那么干过一回. 程序是最真实的答案... 简直是TMD胡扯。 JVM回收是在内存不足的时候.这个已经修正. 不是内存不足才调用。。 你说我胡扯? 那for里定义的局部变量放哪里?不要也和上面一个的观点一样:只申明一次,后调用索引. 这个我不可理解。。 方法的参数连同方法里的变量所占用的空间,在编译时就已经确定了,它决定了运行时一个方法被调用的时侯要分配多大的栈帧。一个变量放在循环外还是循环里,只是在编译期限定了其作用域而已,到了运行时是没有区别的(也许只是在栈帧的local variables区里的位置不同)。 看一下方法的字节码,一切都非常明了: private final int[] numbers = {1, 2, 3, 4, 5}; public void varOutsideLoop() { int n; for (int i = 0; i < numbers.length; i++) { n = numbers[i]; System.out.println(n); } } public void varInsideLoop() { for (int i = 0; i < numbers.length; i++) { int n = numbers[i]; System.out.println(n); } } 对应的字节码: public void varOutsideLoop(); Signature: ()V Code: Stack=2, Locals=3, Args_size=1 0: iconst_0 1: istore_2 2: goto 22 5: aload_0 6: getfield #12; //Field numbers:[I 9: iload_2 10: iaload 11: istore_1 12: getstatic #19; //Field java/lang/System.out:Ljava/io/PrintStream; 15: iload_1 16: invokevirtual #25; //Method java/io/PrintStream.println:(I)V 19: iinc 2, 1 22: iload_2 23: aload_0 24: getfield #12; //Field numbers:[I 27: arraylength 28: if_icmplt 5 31: return LineNumberTable: line 43: 0 line 44: 5 line 45: 12 line 43: 19 line 47: 31 LocalVariableTable: Start Length Slot Name Signature 0 32 0 this Lcom/jstudio/learnjvm/classloader/VarInLoop; 12 10 1 n I 2 29 2 i I public void varInsideLoop(); Signature: ()V Code: Stack=2, Locals=3, Args_size=1 0: iconst_0 1: istore_1 2: goto 22 5: aload_0 6: getfield #12; //Field numbers:[I 9: iload_1 10: iaload 11: istore_2 12: getstatic #19; //Field java/lang/System.out:Ljava/io/PrintStream; 15: iload_2 16: invokevirtual #25; //Method java/io/PrintStream.println:(I)V 19: iinc 1, 1 22: iload_1 23: aload_0 24: getfield #12; //Field numbers:[I 27: arraylength 28: if_icmplt 5 31: return LineNumberTable: line 50: 0 line 51: 5 line 52: 12 line 50: 19 line 54: 31 LocalVariableTable: Start Length Slot Name Signature 0 32 0 this Lcom/jstudio/learnjvm/classloader/VarInLoop; 2 29 1 i I 12 7 2 n I 仔细看字节码就能发现,除了n和循环变量i在local variable table中的位置不同,其他的所有的都没有区别。 varOutsideLoop那个方法里我故意没有初始化n,如果加上初始化,就会多一条iconst和一条istore指令。 至于位置不一样的原因,个人猜测与变量出现的位置有关,n在循环外的版本,它出现在前,所以占据了第一个slot(第0个slot是对象本身,即this);n在循环里的版本,循环变量i出现在前,所以i占据了第一个slot,而n占用的是第二个slot。 除此之外,两个方法没有任何的区别。 mercyblitz 写道 主要你误解了a变量在遍历中,有入栈和出栈的操作。并没有重复开辟局部变量,再说JVM优化之后,不会重复创建。 个人认为这种说法也不太对,在一个方法内部不会有所谓的“入栈”和“出栈”操作。方法里,一个变量占用一个local variable table的slot,一个萝卜一个坑。所有这些变量都是在方法结束,堆栈帧被销毁的时侯才真正被“回收”,即使方法结束的时侯它早以超出了自己的作用域…… 实践中,变量的作用域当然是尽可能小才好,即有利于垃圾收集、也消除了一些潜在的导致bug的隐患。 楼主别理那个“代码评审官”就好……话说如果我遇到这种人这种事,我八成不愿继续干下去…… 恩,谢谢指正,我也仔细想了一下。在楼主的例子中,字节码说明两个局部变量指向不同的地方。不会重复开辟。要想开辟更多,哪么需要不同名称的变量申明。 |
|
返回顶楼 | |