簡體   English   中英

以非完全編譯語言(例如Java)存儲在堆還是堆棧中的變量?

[英]Variables stored on heap vs. stack in a non-fully compiled language (e.g. Java)?

我正在學習Java並閱讀如何將原語(在方法中定義)存儲在“堆棧”中,以及將其他內容存儲在“堆”中。

但是,Java不是完全編譯為可執行語言的語言,因此將事物存儲在“堆棧”中意味着什么?

我認為,JVM在讀取字節碼時必須使用malloc / new / etc獲取所有內容的存儲。

像Python這樣的語言也是如此(盡管我沒有讀過Python在堆棧上存儲變量的任何地方,所以對我來說沒有什么困惑)。 由於這些語言是可解釋的,因此解釋器在遇到變量定義時將不得不為其動態分配內存,對嗎?

語言只是一種抽象。 只要實現提供語言規范規定的結果,任何實現都是允許的。

當有人說原語存儲在堆棧上而對象存儲在堆上時,它們真正的意思是那是實現解釋器的自然方式。 實際上,您很可能會使用JIT,在這種情況下,有時也可以將對象存儲在堆棧中。 但這都是抽象的實現細節,因此您不必關心它。 如果這樣做,則需要找出正在使用的特定VM的工作方式。

Java不是完全編譯為可執行語言的語言,因此將事物存儲在“堆棧”中意味着什么?

不在第一步。 但是,當您開始運行Java程序時,JIT會將代碼編譯為機器語言。 如果沒有,您將無法運行任何Java程序。 任何程序都應打開或使用現有的機器代碼才能運行。

我認為,JVM在讀取字節碼時必須使用malloc / new / etc獲取所有內容的存儲。

為了在堆棧上分配數據,您(通常)向前或向后移動堆棧指針 (取決於堆棧體系結構)。 例如在MASM語法上,為了分配1個4字節大小的整數,需要從堆棧指針中減去4個字節:

sub esp,4 //sub = subtract , esp = extended stack pointer

我為什么要告訴你這一切? 因為當JIT看到類似

int x; //or intermidiate language equivilant

它可以將其轉換為

sub esp,4

因此在堆棧上分配整數。

但是我想我知道混亂的根源。
堆棧和堆分配均在運行時完成

唯一的例外是C(和C ++)堆棧的分配大小是靜態的-該大小在編譯時確定,而動態分配大小在運行時確定(或可以更改)。
JIT在運行時編譯代碼,但是它將堆棧分配的大小硬編碼為組合代碼,因此該大小是“靜態的”。

堆棧只是以某種方式管理的內存區域。 該規范不需要特定的分配策略,但最后,JVM 總是必須以任何一種方式分配所需的內存,而不管要執行的代碼是已編譯還是已解釋。

這與以直接編譯為本機代碼的編程語言開發的程序沒有什么不同。 程序仍然必須為堆棧分配內存,盡管它可能在后台發生(從應用程序程序員的角度來看,在Java中也可能在后台發生)。

但是看來,您對堆棧的想法還是有誤的。 包括Java在內的大多數現代編程語言都以框架形式組織堆棧。 框架能夠保存方法中可能遇到的所有局部變量和最深的操作數堆棧。 方法的幀直接在方法的入口處分配,並且在執行或解釋方法的字節碼的過程中不執行其他分配。

換句話說,Java的字節碼指令集沒有要處理的“變量定義”之類的東西。 只有指令在局部變量(由索引尋址)與操作數堆棧之間或在操作數堆棧與堆之間傳輸項目。 局部變量的存在暗示着已經寫入了局部變量。 有一些可選的調試信息,提示在哪個代碼位置應該存在哪些變量,但是在正常執行期間不會處理這些信息。

根據JVM的實現,每個線程可能具有一個固定的最大堆棧大小的預分配內存存儲空間,在其中放置了堆棧幀。 在這些實現中,在線程的生存期內,不對堆棧執行操作系統操作意義上的分配。 許多本機代碼遵循相同的模型。

暫無
暫無

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

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