簡體   English   中英

Java中的靜態方法和靜態變量存儲在哪里?

[英]Where are static methods and static variables stored in Java?

例如:

class A {
    static int i=0;
    static int j;

   static void method() {
       // static k=0; can't use static for local variables only final is permitted
       // static int L;
    }
}

這些變量將存儲在 Java 中的什么位置、堆內存或堆棧內存中? 它們是如何存儲的?

靜態方法(實際上是所有方法)和靜態變量都存儲在堆的PermGen部分中,因為它們是反射數據的一部分(與類相關的數據,而不是與實例相關的數據)。 從 Java 8 開始,PermGen 已被 MetaSpace 取代,根據JEP 122 ,它只保存元數據,而靜態字段存儲在堆中。

請注意,這主要適用於 Oracle 的 Hotspot JVM 和其他基於它的。 然而,並不是每個 JVM 都擁有像Eclipse OpenJ9 這樣的 PermGen 或 Metaspace

更新澄清

請注意,只有變量及其技術值(基元或引用)存儲在 PermGen 空間中。

如果您的靜態變量是對對象的引用,則該對象本身存儲在堆的正常部分(年輕/老一代或幸存者空間)中。 這些對象(除非它們是類等內部對象)存儲在 PermGen 空間中。

例子:

static int i = 1; //the value 1 is stored in the PermGen section
static Object o = new SomeObject(); //the reference(pointer/memory address) is stored in the PermGen section, the object itself is not.

關於垃圾收集的一句話:

不要依賴finalize()因為它不能保證運行。 完全由 JVM 來決定何時運行垃圾收集器以及收集什么,即使一個對象有資格進行垃圾收集。

當然,您可以將靜態變量設置為 null,從而刪除對堆上對象的引用,但這並不意味着垃圾收集器收集它(即使沒有更多引用)。

此外finalize()只運行一次,因此您必須確保它不會引發異常或以其他方式阻止對象被收集。 如果您通過某些異常停止終結,則不會在同一對象上再次調用finalize()

最后一點:如何存儲代碼、運行時數據等取決於所使用的 JVM,即 HotSpot 的執行方式可能與 JRockit 不同,甚至在同一 JVM 的版本之間也可能有所不同。 以上基於 Java 5 和 6 的 HotSpot(它們基本相同),因為在回答時我會說大多數人都使用這些 JVM。 由於 Java 8 的內存模型發生了重大變化,上述陳述對於 Java 8 HotSpot 可能不正確——而且我沒有檢查 Java 7 HotSpot 的變化,所以我上述對於那個版本仍然是正確的,但我不確定這里。

在 Java 8 之前:

靜態變量存儲在 permgen 空間(也稱為方法區)中。

PermGen 空間也稱為方法區

PermGen Space 用來存放 3 樣東西

  1. 類級數據(元數據)
  2. 實習字符串
  3. 靜態變量

從 Java 8 開始

靜態變量存儲在堆本身中。從 Java 8 開始,PermGen Space 已被刪除,並引入了名為 MetaSpace 的新空間,它不再是 Heap 的一部分,與以前的 Permgen Space 不同。 元空間存在於本機內存(由操作系統提供給特定應用程序以供其使用的內存),它現在只存儲類元數據。

內部字符串和靜態變量被移動到堆本身。

有關官方信息,請參閱: JEP 122:Remove the Permanent Gen Space

類變量(靜態變量)存儲為與該類關聯的Class object的一部分。 這個 Class 對象只能由 JVM 創建,並且存儲在permanent generation中。

也有人回答說它存儲在稱為Method Area. 即使這個答案也沒有錯。 Permgen 區域是否是堆的一部分只是一個有爭議的話題。 顯然,每個人的認知是不同的。 在我看來,我們在 JVM 參數中以不同的方式提供堆空間和永久空間。 因此,以不同的方式對待它們是一個很好的假設。

另一種看待它的方式

內存池由 JVM 內存管理器在運行時創建。 內存池可能屬於堆內存或非堆內存。運行時常量池是類文件中常量池表的按類或按接口運行時表示。 每個運行時常量池都是從 Java 虛擬機的方法區分配的,靜態變量存儲在這個方法區中。 這個非堆也只不過是 perm gen 區域。實際上 Method area 是 perm gen 的一部分。(參考

在此處輸入圖像描述

這是一個有簡單答案和冗長答案的問題。

簡單的答案是堆。 類和應用於類的所有數據(不是實例數據)存儲在堆的永久代部分中。

長答案已經在堆棧溢出:

對 JVM 中的內存和垃圾收集進行了全面的描述,以及更簡潔地討論它的答案

它存儲在類定義引用的堆中。 如果您考慮一下,它與堆棧無關,因為沒有范圍。

除了托馬斯的答案,靜態變量存儲在稱為方法區的非堆區域中。

由於靜態變量是類級別的變量,它們將存儲“永久代”的堆內存。 有關 JVM 的更多詳細信息,請查看內容。 希望這會有所幫助

靜態變量存儲在堆中

當我們創建一個靜態變量或方法時,它存儲在堆上的特殊區域:PermGen(Permanent Generation),在那里它放置了應用於類的所有數據(非實例數據)。 從 Java 8 開始,PermGen 變成了 - Metaspace。 不同之處在於 Metaspace 是自動增長的空間,而 PermGen 有一個固定的 Max 大小,並且這個空間在所有實例之間共享。 另外,元空間是本機內存的一部分,而不是 JVM 內存。

您可以查看內容以獲取更多詳細信息。

在現實世界或項目中,我們事先有需求,需要在類中創建變量和方法,根據需求我們需要決定是否需要創建

  1. 本地(在塊或方法構造函數中創建 n 訪問)
  2. 靜止的,
  3. 實例變量(每個對象都有自己的副本),

=> 2。 靜態關鍵字將與變量一起使用,該變量對於所有對象的特定類將是相同的,

例如在 selenium 中:我們將 webDriver 標記為靜態 => 所以我們不需要為每個測試用例一次又一次地創建 webdriver

Static Webdriver driver

(但並行執行會導致問題,但那是另一種情況);

現實世界場景 => 如果印度是階級,那么國旗,每個印度人的錢都是一樣的,所以我們可以把它們當作靜態的。

另一個例子:我們總是聲明為靜態 b'cos 的實用方法,它將在不同的測試用例中使用。 靜態存儲在 CMA(PreGen 空間)=PreGen(固定內存)在 Java8 之后更改為 Metaspace,因為它現在動態增長

從 Java 8 開始,PermGen 空間已過時。 靜態方法、基元和引用變量存儲在 Java 元空間中。 實際對象駐留在 JAVA 堆中。 由於靜態方法永遠不會脫離引用,因此它們永遠不會從 MetaSpace 和 HEAP 中收集垃圾。

暫無
暫無

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

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