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 循環體里面會有兩個局部變量p1和p2,他們也會在局部變量表中占用兩個槽位。在每一次循環中,new Person() 這個語句都會在堆內存創建一個新的對象,并且把p1變量指向這個新建的對象,隨后p2 也會指向相同的對象。所以這個例子里面,堆內存中會在不停地創建對象,而這個大量對象的創建,會觸發到堆內存里面的垃圾回收,垃圾回收器會把這些創建后又沒使用的一大堆Person對象給回收掉。所以這個過程就是在 “不停創建” – “垃圾回收”之間來回切換,進而導致內存的占用會忽上忽下,這種現象也被稱為“內存抖動”。“內存抖動”是比較耗性能的,應該在實際應用中盡量避免。
綜上,題目中的兩個問題,簡單來說就是:while語句中的變量都是在局部變量表中占用了一個槽位,并且對這個槽位反復讀寫,所以稱不上是“回收”。
參考地址:https://www.zhihu.com/question/439157488
總結
以上是生活随笔為你收集整理的Java 中把声明变量的语句如果写在循环体内,每次执行时栈内存中的变量和数据是如何变化的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 索尼 PSN 商店“Plus 双倍折扣优
- 下一篇: 如何理解Java的类变量、成员变量、常量