Java 中把声明变量的语句如果写在循环体内,每次执行时栈内存中的变量和数据是如何变化的?
问题一:如下面的代码示例 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 中把声明变量的语句如果写在循环体内,每次执行时栈内存中的变量和数据是如何变化的?相关推荐
- 【C 语言】结构体 ( 结构体类型定义 | 结构体类型别名 | 声明结构体变量的三种方法 | 栈内存中声明结构体变量 | 定义隐式结构体时声明变量 | 定义普通结构体时声明变量 )
文章目录 一.结构体类型定义 二.结构体类型别名 三.结构体类型变量声明 1.使用结构体类型 ( 别名 ) 声明变量 2. 定义隐式结构体时声明变量 3.定义普通结构体时声明变量 二.完整代码示例 一 ...
- Java对象运行时在内存中的情况
Java对象运行时在内存中的情况 您可能已经知道,一旦创建了一个对象,它就只是堆中的一系列字节.您可能对Java对象在内存中的情况感到好奇吗? 1.变量 以下是"Base"(B)类 ...
- 查询一个表中所有id字段在另一个表中对应值的SQL语句怎么写?
编辑器加载中... 查询一个表中所有id字段在另一个表中对应值的SQL语句怎么写?多表联结查询:select rbd.RBDID, rbd.ProductCode,p.ProductCnName,p. ...
- LSM树——放弃读能力换取写能力,将多次修改放在内存中形成有序树再统一写入磁盘...
LSM树(Log-Structured Merge Tree)存储引擎 代表数据库:nessDB.leveldb.hbase等 核心思想的核心就是放弃部分读能力,换取写入的最大化能力.LSM Tree ...
- LSM树——放弃读能力换取写能力,将多次修改放在内存中形成有序树再统一写入磁盘,查找复杂度O(k*log(n)),结合bloom filter提高查找性能...
来自:http://www.open-open.com/lib/view/open1424916275249.html 十年前,谷歌发表了 "BigTable" 的论文,论文中很多 ...
- python函数 模块先加载到内存后执行_Python从内存中使用编译后的模块
在Windows编程的时候,有些时候,我们经常会要使用一些非常规的方法,比如说从内存中加载DLL,然后使用DLL中的函数.于是就思索在用Python的时候是否能够将几个编译好的Pyc合并成一个,然后使 ...
- C99中带声明的for语句
计算整数n的所有正因子之和. C99之前for语句的格式如下: for(表达式1;表达式2;表达式3) 语句 例如: int i; for(i=0;i<n;i++) ... 表达式1是循环开始执 ...
- oracle中删除表字段 sql语句怎么写,oracle使用sql语句增加字段示例(sql删除字段语句)...
添加字段的语法:alter table tablename add (column datatype [default value][null/not null],-.); 修改字段的语法:alter ...
- oracle 数据库循环查询语句怎么写,sql循环查询(sql语句循环查询详解)
sql循环查询(sql语句循环查询详解) 2020-07-24 11:15:51 共10个回答 select*fromawheret_idin('3','4');select*fromawheret_ ...
最新文章
- JVM内存调优原则及几种JVM内存调优方法
- 转 DevExpress-ASPxPageControl 动态添加 TabPage 内容
- stl里面stack的注意事项
- 你是一个优秀的IT PRO吗?(下篇)
- 移动端AI应用太抢手,高通这次要送开发者20万+的SUV
- Python Web开发框架Django
- 十-二进制数的最少数目
- oseasy还原卡_学校机房管理批量更新软件的问题还原卡、网刻、噢易OSS对比区别...
- mac 文字识别软件ocr_树洞OCR文字识别for Mac-树洞OCR文字识别Mac版下载 V1.2.0-PC6苹果网...
- python输入直角三角形两条直角边、输出斜边长_用C++输入直角三角形的两条直角边长,调用平方根函数sqrt来求斜边的长度。...
- 不确定性Uncertainty
- 【计算大于这个整数的最小质数】
- (第十三届蓝桥杯省赛)试题J:砍竹子(优先队列+模拟)
- 新美域杂志新美域杂志社新美域编辑部2022年第6期目录
- vue单页面SEO优化
- 区块链网络管理平台WeBASE双节点可视化部署
- MOSFet cutoff frequency ( From google)
- DSM-830源网荷系统控制终端(源网荷智能互动终端)-新型电力负荷控制终端(电力负荷管理终端装置)-互动式需求侧管理终端-专变采集终端的功能。DSM-830交互式需求侧管理终端(需求侧管理互动式终端
- gsoc 任务_gsoc 2020最终报告wikimedia transferpy改进
- 学习使用微信小程序动态获取当前时间并实时跳动
热门文章
- java 示例_功能Java示例 第5部分–将I / O移到外部
- java 错误输入异常_在Java中进行输入验证期间用错误通知替换异常
- jpa语法错误_JPA陷阱/错误
- hibernate与jpa_将JPA Hibernate与OptaPlanner集成
- REST /使用提要发布事件
- OpenHub框架进行的异步通信
- Java命令行界面(第19部分):jClap
- Java数据类型和标识符
- java中无法推断类型参数_Java中的推断异常
- servlet3.0新特性_查看Servlet 3.0的新增功能