簡體   English   中英

堆棧垃圾是用Java收集的嗎?

[英]Is the stack garbage collected in Java?

堆內存是用Java收集的。

堆棧垃圾也收集了嗎?

如何回收堆棧內存?

堆棧中的內存包含方法參數和局部變量(准確地說:對象的引用和基本類型的變量本身)。 如果您離開方法,將自動刪除。 如果變量是引用(對象),則對象本身位於堆上並由垃圾收集器處理。

因此,堆棧不是以與堆相同的方式進行垃圾收集,而是堆棧是一種自動內存管理形式(在垃圾收集之前)。

Thomas Pornin給出了一個更詳細的答案 ,請查看更多細節。

堆棧不是用Java收集的垃圾。

方法返回時,將釋放為給定方法調用分配的堆棧。 由於這是一個非常簡單的LIFO結構,因此不需要垃圾收集。

堆棧和垃圾收集交互的一個地方是堆棧上的引用是GC根(這意味着它們是決定可達性的根引用)。

堆棧可能是垃圾收集。 但是,在大多數JVM實現中,它被處理為“堆棧”,根據定義,它排除了垃圾收集。

我們稱之為堆棧的是方法激活上下文的累積:對於每個被調用的方法,這是概念結構,其包含方法參數,局部變量,指向調用方法的上下文的隱藏指針,以及用於保存指令的槽。指針。 激活上下文不能從Java語言本身訪問。 當方法退出時( return或由於拋出的異常),上下文變得無用。 碰巧當方法A調用方法B時,可以保證當A重新獲得控制時,B的上下文變得無用。 這意味着B的上下文的生存期是A的上下文生命周期的子范圍。因此,激活上下文(對於給定的線程)可以使用LIFO(“后進先出”)規則進行分配。 簡單來說,就是一個堆棧:一個新的激活上下文被推送到一堆上下文之上,而頂層的上下文將是第一個被處理掉的。

實際上,激活上下文(也稱為堆棧幀 )以堆棧順序在專用區域中連接。 該區域是在線程啟動時從操作系統獲得的,操作系統在線程終止時將其返回。 堆棧的頂部由特定指針指定,通常包含在CPU寄存器中(這取決於JVM是解釋還是編譯代碼)。 “指向調用者上下文的指針”是虛擬的; 調用者的上下文必須位於堆棧順序的下方。 GC不會介入:從線程活動本身創建並同步回收堆棧區域。 這也是它在許多語言中的工作方式,例如C ,它根本沒有GC。

現在沒有什么能阻止JVM實現做其他事情,例如在堆中分配激活上下文並由GC收集它們。 這通常不在Java虛擬機中完成,因為堆棧分配更快。 但是其他一些語言需要做這樣的事情,最值得注意的是那些在使用GC時繼續玩游戲的東西(例如Scheme及其call-with-current-continuation函數),因為這些游戲打破了上面解釋的LIFO規則。

內存的堆棧部分就像“堆棧”一樣工作。 我知道這聽起來很糟糕,但這正是它的工作原理。 數據被添加到頂部,彼此pushed onto the stackpushed onto the stack )並在程序運行時自動從頂部( popped off the stack )中刪除。 它不是垃圾收集 - 並且它不需要是因為一旦數據從堆棧彈出就自動回收內存。 當我說回收時,我並不是說它被取消分配 - 只是當數據被彈出時,堆棧存儲器中存儲下一個數據的位置會減少。

當然,這並不是說你根本不需要擔心堆棧。 如果多次運行遞歸函數,它最終將耗盡所有堆棧空間。 如果調用許多函數,則相同,特別是如果它們有許多參數和/或局部變量。

但最重要的是,當函數自動進入和離開范圍時,使用並回收堆棧的內存。 因此,在程序執行結束時,所有堆棧內存都將是空閑的,然后釋放回操作系統。

如果您引用堆棧上使用的內存,則不會進行垃圾回收。
java虛擬機使用顯式字節碼指令來保留和釋放堆棧上的內存,這些指令由編譯器生成並管理堆棧上的int,boolean,double和object-references等基元的生命周期。
已經有計划實現一個所謂的尾調用優化,一旦知道它們不再被使用就會從棧中刪除一些條目,但我不知道任何已經支持它的jvm。
因此,堆棧本身沒有垃圾收集,只有編譯器生成了push和pop指令來管理內存使用。

堆棧本身是線程的一部分。 在創建線程對象時分配堆棧,並在線程終止並且不再引用線程對象之后收集垃圾。

Java中的所有對象都在堆上分配。 (至少就規范而言,實際的實現可能會將它們分配到堆棧上,如果它們透明地表現就像它們在堆上一樣。)

究竟什么是收藏品有點微妙。 如果對象的唯一引用位於單個堆棧幀中,並且可以顯示將不再使用引用,則可以收集該對象。 如果對象僅用於讀取字段,則可以向前優化該字段讀取,並且比您預期的更早收集對象。

除非您使用的是終結者(或推測Reference ),否則這通常不重要。 在這種情況下,您應該小心並使用locks / volatile來強制執行happens-before關系。

當線程停止時,通常會釋放整個堆棧。

堆棧中的所有內容都被垃圾收集器視為全局根。 所以,是的,你肯定可以說堆棧是“垃圾收集”。

沒有人,數據會從堆棧中推送和彈出,因為你在方法,方法調用等過程中有內部變量。你不需要關心這一點。

不。堆棧不是用Java收集的垃圾。 每個線程都有自己的堆棧,包含:

  1. 方法特定值(短期)和
  2. 引用在堆上創建的對象,並由方法引用

對於每個方法調用,這些值作為堆棧幀被推送到堆棧。 由於堆棧遵循“后進先出”順序,因此在每次方法調用結束時,將彈出包含所有方法特定數據和對象引用(如果有)的每個堆棧幀。

因此,一旦方法/程序超出范圍,堆棧中的數據將自動清除。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM