1. 程式人生 > >解釋記憶體中的棧(stack)、堆(heap)和方法區(method area)的用法

解釋記憶體中的棧(stack)、堆(heap)和方法區(method area)的用法

        通常我們定義一個基本資料型別的變數,一個物件的引用,還有就是函式呼叫的現場儲存都使用JVM中的棧空間;而通過new關鍵字和構造器建立的物件則放在堆空間,堆是垃圾收集器管理的主要區域,由於現在的垃圾收集器都採用分代收集演算法,所以堆空間還可以細分為新生代和老生代,再具體一點可以分為Eden、Survivor(又可分為From Survivor和To Survivor)、Tenured;方法區和堆都是各個執行緒共享的記憶體區域,用於儲存已經被JVM載入的類資訊、常量、靜態變數、JIT編譯器編譯後的程式碼等資料;程式中的字面量(literal)如直接書寫的100、"hello"和常量都是放在常量池中,常量池是方法區的一部分,。棧空間操作起來最快但是棧很小,通常大量的物件都是放在堆空間,棧和堆的大小都可以通過JVM的啟動引數來進行調整,棧空間用光了會引發StackOverflowError,而堆和常量池空間不足則會引發OutOfMemoryError。

String str = new String("hello");
  • 1

上面的語句中變數str放在棧上,用new創建出來的字串物件放在堆上,而"hello"這個字面量是放在方法區的。

補充1:較新版本的Java(從Java 6的某個更新開始)中,由於JIT編譯器的發展和"逃逸分析"技術的逐漸成熟,棧上分配、標量替換等優化技術使得物件一定分配在堆上這件事情已經變得不那麼絕對了。

補充2:執行時常量池相當於Class檔案常量池具有動態性,Java語言並不要求常量一定只有編譯期間才能產生,執行期間也可以將新的常量放入池中,String類的intern()方法就是這樣的。

看看下面程式碼的執行結果是什麼並且比較一下Java 7以前和以後的執行結果是否一致。

String s1 = new StringBuilder("go")
    .append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja")
    .append("va").toString();
System.out.println(s2.intern() == s2);