「每日五分鐘,玩轉JVM」:線程共享區

前言

上一篇中,咱們瞭解了JVM中的線程獨佔區,這節課咱們就來了解一下JVM中的線程共享區,JVM中的線程共享區是跟隨JVM啓動時一塊兒建立的,包括堆(Heap)和方法區(Method Area)兩部分,而線程獨佔區的程序計數器,虛擬機棧,本地方法棧的生命週期都是跟隨線程的,隨線程的建立而誕生,隨線程的銷燬而銷燬。java

堆(Heap)

堆內存做爲JVM管理的內存中最大的一塊,用於存放咱們的對象實例,咱們常常會把JVM的內存簡單的分爲堆內存和棧內存,這樣說雖然有些片面,可是也有這麼說的道理,這兩塊兒一個做爲執行程序的,一個做爲存放對象的,是JVM中最爲重要的兩塊兒內存。因此,咱們的垃圾收集通常是針對的用於存放對象的堆內存,因此堆內存有時候也會被稱爲GC堆。緩存

從內存分配的角度上來講,堆內存中包含了新生代內存和老年代內存,而年輕代又分爲Eden和Survivor區。Survivor區由From Survivor和To Survivor組成。Eden區佔大容量,Survivor兩個區佔小容量,默認比例是8:1:1,並且JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來爲對象服務,因此不管何時,老是有一塊 Survivor 區域是空閒着的。bash

這樣設計的緣由是爲了更方便的進行垃圾收集,咱們會在後面垃圾收集的章節中去詳細的講解。學習

TLAB

TLAB的全稱是Thread Local Allocation Buffer,即線程本地分配緩存區,這是一個處於堆內存中線程私有的內存分配區域,默認狀況下這個區域就是開啓的,固然咱們也能夠在啓動時配置XX:+UseTLAB去開啓該區域,這個區域所佔空間很是的小,默認狀況下只佔Eden區域的1%,咱們也能夠經過也XX:TLABWasteTargetPercent設置TLAB空間所佔用Eden空間的百分比大小。spa

方法區

方法區存儲虛擬機加載的類信息常量靜態變量,即時編譯器編譯後的代碼等數據,在Java虛擬機的規範中,把方法區認爲是堆內存的邏輯部分,可是實際上他們是徹底隔離的。線程

在JDK 8 以前,方法區被稱爲(或者能夠說是被實現爲)持久代,永久代(Perman Gen),而在 JDK 8 以後,取消了永久代的概念,取而代之的實現是元空間(MetaSpace),本來位於永久代中的運行時常量池和靜態變量都存儲到了堆中,而其他的內容則是移到了元空間。設計

元空間的本質和永久代相似,都是對JVM規範中方法區的實現,它們之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。所以,默認狀況下,元空間的大小僅受本地內存限制,但能夠經過如下參數來指定元空間的大小:-XX:MetaspaceSize-XX:MaxMetaspaceSizecode

因此咱們前幾年JDK7盛行的時候OOM錯誤消息是這樣的:cdn

java.lang.OutOfMemoryError:PermGen space
複製代碼

而在近幾年JDK8的使用中遇到的OOM是這樣的:對象

java.lang.OutOfMemoryError:Metaspace
複製代碼

運行時常量池

運行時常量池位於元空間中,用於存儲編譯期生成的各類字面量和符號引用,而這裏須要注意一點:字符串常量池從JDK 7 以後就移到了堆內存中去管理,可是運行時常量是仍然位於方法區基於JDK 8 的新實現——元空間中。

網上有部分聲音說運行時常量池在JDK8移到了堆內存中,其實這種說法是錯誤的,真正移到堆內存的是字符串常量池,而且是在JDK7的更新中就已經移到了堆中。

更詳細的關於常量池的信息咱們會在類結構中去學習。

後話

天天五分鐘,跟Vi玩轉JVM!

下篇解密一個對象的誕生!

公衆號

本文首發於公衆號,掃碼關注便可獲取最新文章

相關文章
相關標籤/搜索