概述
问题一:如下面的代码示例 1,JVM 是不是会反复回收旧的变量 a 再重新创建新的变量 a 呢?还是旧的变量 a 一直保留在栈内,只是反复赋值 0 而已呢?
代码示例 1:
while (true) {
int a = 0;
a = 5;
}
问题二:如下面的代码示例 2,循环体内的引用数据类型变量 p3 是否会先回收再新建,还是保留旧的变量 p3,只是反复对其赋值而已呢?
代码示例 2:
Person p1 = new Person();
Person p2 = new Person();
while (true) {
Person p3 = p1;
p3 = p2;
}
正确答案:旧变量依旧保留在栈内,只是反复赋值。
基本类型变量 a
和引用类型变量 p3
都不会因为声明变量的语句在循环体内而不断地重新创建,变量一直存在栈内存中,只是循环的赋值而已,只是循环地对变量 a
和变量 p3
读写数据而已。
参考答案:
首先,先明白一个概念,什么是“回收”?
大家都知道,JVM的内存结构有两个主要的区域:堆内存和栈内存。
那么回收也是有相应的两个层面的:
- 在堆内存里面发生的回收:由垃圾回收器进行回收,会把不再可用的对象进行回收。
- 在栈内存里面发生的回收:栈内存是由栈帧组成的,局部变量都是在栈帧里面定义的,所以局部变量的回收,是随着栈帧的销毁而被回收的。而栈帧的销毁,是在方法调用完成之后。
在弄清楚“回收”的概念之后,再回到问题。
先看问题1:
这段代码里面,很明显,变量a是一个局部变量,而且是原始类型的局部变量,所以它的内存分配是在栈上,确切地说是在栈帧里面的局部变量表里面。而局部变量表这个东西,是在编译期间就确定的,它类似一个数组,里面包含了一些“槽位”来存放局部变量。那么,a这个变量,就是在局部变量表中的某一个槽位里面。并且a只会占用一个槽位,while循环里面来来回回也是对这一个槽位的里面进行读写。这个严格来说,算不上是“回收”。
再看问题2:
问题2和问题1基本上一样的,在while 循环体里面只是对局部变量表的一个槽位来进行读写。和问题1有点区别的地方只是,p1和p2两个对象都是引用类型的,他们分别指向了堆内存的两个对象,并且这两个位于堆内存中的对象是没有变化的。
再看问题3:
顺着题主的思路,我猜测应该还有一种情况也是题主关心的,就是下面这种情况:
while (true) {
Person p1 = new Person();
Person p2 = p1;
}
在这种情况里面,while 循环体里面会有两个局部变量p1和p2,他们也会在局部变量表中占用两个槽位。在每一次循环中,new Person() 这个语句都会在堆内存创建一个新的对象,并且把p1变量指向这个新建的对象,随后p2 也会指向相同的对象。所以这个例子里面,堆内存中会在不停地创建对象,而这个大量对象的创建,会触发到堆内存里面的垃圾回收,垃圾回收器会把这些创建后又没使用的一大堆Person对象给回收掉。所以这个过程就是在 “不停创建” – “垃圾回收”之间来回切换,进而导致内存的占用会忽上忽下,这种现象也被称为“内存抖动”。“内存抖动”是比较耗性能的,应该在实际应用中尽量避免。
综上,题目中的两个问题,简单来说就是:while语句中的变量都是在局部变量表中占用了一个槽位,并且对这个槽位反复读写,所以称不上是“回收”。
参考地址:https://www.zhihu.com/question/439157488
最后
以上就是美满戒指为你收集整理的Java 中把声明变量的语句如果写在循环体内,每次执行时栈内存中的变量和数据是如何变化的?的全部内容,希望文章能够帮你解决Java 中把声明变量的语句如果写在循环体内,每次执行时栈内存中的变量和数据是如何变化的?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复