1. 程式人生 > >JVM記憶體中的年輕代,老年代

JVM記憶體中的年輕代,老年代

引言

對於大多數Java應用來說,Java Heap(Java堆)是JVM管理的記憶體中較大的一塊,而且Java Heap是被所有執行緒共享的一塊記憶體區域,於虛擬機器啟動時建立。

而Java堆的唯一目的就是存放物件例項。

由於Java堆是垃圾收集器管理的主要區域,因此也被稱為"GC堆"。

再從記憶體回收的角度來看,由於現代收集器基本都採用分代收集演算法,所以Java Heap還可以被細分為:

新生代和老年代,新生代再分得細緻一點就可以分為Eden空間和兩個相同大小相同的Survivor空間,下面來談談新生代和老年代。

新生代

通俗理解就是新建立的物件就是先進入新生代,然後建立久而且還未被回收的物件自然而然就進入老年代。

上面說了,年輕代又分為一個Eden空間和兩個Survivor空間,這樣分的意義是什麼呢,這裡不得不說一下一個垃圾收集演算法:

複製演算法:

這裡不得不又介紹一下

傳統的標記清除演算法:就是首先標記出所有需要回收的物件,在標記完成後統一回收所有被標記的物件。

該演算法有如下缺點:
   1.效率問題
   2.空間問題,標記清除之後會產生大量不連續的記憶體碎片,空間碎片太多可能會導致以後在程式執行過程中需要分配較大物件時,無法找到足夠的連續記憶體而不得不提前出發另一次垃圾收集動作。

(圖是截書上的,應該看得清吧)

所以複製演算法就是主要為了解決以上的缺點,複製演算法就是將可用記憶體按容量劃分為大小相等兩塊,每次只使用其中的一塊,

當這一塊的記憶體用完了,就將還存活著的物件複製道另外一塊上面,然後再把已使用過的記憶體空間一次清理掉,這樣每次都是對整個半區進行記憶體回收,所以記憶體分配時也就不用去考慮記憶體碎片等複雜情況了,但是這種演算法也有一個很明顯的缺點,會縮小實際可以使用的記憶體,這裡就直接縮小了一半!

而其實年輕代這樣分配Eden和兩個兩個Survivor其實就是採用了複製演算法的思想,不過這就沒有每次都只使用一次這麼誇張,這裡年輕代每次都只使用Eden和一個Survivor,即新建立的物件都放入Eden和一個Survivor,如果記憶體不夠,就會先把這兩個空間上還存活的物件放入另一個Survivor空間,然後進行Minor GC。

而新生代為什麼要採用這種演算法呢,這是因為新生代的物件大部分都是“朝生夕死”,因此這裡雖然採用了複製演算法的思想,但是並不需要按1:1來劃分空間,而只需要分配一小部分空間給Survivor即可,HotSpot虛擬機器預設Eden和Survivor比例是8:1 ,即每次新生代可用記憶體空間為90%,當然如果在這種情況下由超過10%的物件存活(因為這裡一個Survivor空間只有10%),即進行過一次Minor GC之後,一個Survivor空間裝不下存活的物件,這就需要老年代進行分配擔保了。

設定新生代空間:

1.直接對新生代大小進行設定  -Xmn   例如:-Xmn10M   新生代大小為10M(eden+ 2 survivor space)

2.通過設定老年代與新生代的比例來設定  -XX:NewRatio 例如:-XX:NewRatio=4 

(表示年輕代與年老代所佔比值為1:4,年輕代佔整個堆疊的1/5,Xms=Xmx並且設定了Xmn的情況下,該引數不需要進行設定)

設定Eden與Survivor的比例:-XX:SurvivorRatio 例如:-XX:SurvivorRatio=8

(則兩個Survivor區與一個Eden區的比值為2:8,一個Survivor區佔整個年輕代的1/10)

老年代

上面說過經過Minor GC之後,如果Survivor存放不下存活的物件,物件就會通過分配擔保機制進入老年代,而如果老年代空間還不夠,就會進行Full GC。

老年代使用的回收演算法是標記整理演算法:

該演算法也有標記過程,和標記清除演算法一樣,但是後面不是直接對可回收物件進行清理,而是讓所有存活的物件都向一端移動,然後直接清理掉端邊界以外的記憶體:

進入老年代除了以上那種情況還有以下情況:

1.大物件直接進入老年代

大物件是需要大量連續記憶體空間的Java物件,最典型的大物件就是那種很長的字串以及陣列,
經常出現大物件容易導致記憶體還有不少空間時就提前出發垃圾收集以獲取足夠的連續空間來安置它們。

虛擬機器提供了 -XX:PretenureSizeThreshold引數,令大於這個設定值的物件直接在老年代分配,
目的是避免在Eden區以及兩個Survivor區之間發生大量的記憶體賦值(新生代採用複製演算法收集記憶體)
 

2.長期存活的物件即將進入老年代

虛擬機器給每個物件定義了一個物件年齡計數器,如果物件在Eden出生並經過第一次Minor GC後仍然存活,並且能被Survivor容納的話,將被移動道Survivor空間,並且物件年齡設為1,並且每經過一次Minor GC,就會多一歲,當達到一定值時,就會被移動道老年代(預設為15),可以通過設定-XX:MaxTenuringThreshold設定。

3.動態物件年齡繫結

如果在Survivor空間中相同年齡所有物件大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的物件就可以直接進入老年代。

相關推薦

JVM記憶體年輕年代永久

Java 中的堆是 JVM 所管理的最大的一塊記憶體空間,主要用於存放各種類的例項物件,如下圖所示:  在 Java 中,堆被劃分成兩個不同的區域:新生代 ( Young )、老年代 ( Old)。新生代 ( Young ) 又被劃分為三個區域:Eden、S0、S1。 這樣劃分的目的是

JVM記憶體年輕年代

引言 對於大多數Java應用來說,Java Heap(Java堆)是JVM管理的記憶體中較大的一塊,而且Java Heap是被所有執行緒共享的一塊記憶體區域,於虛擬機器啟動時建立。 而Java堆的唯一目的就是存放物件例項。 由於Java堆是垃圾收集器管理的主要區域,因此

jvm裡面年輕年代永久元空間

1.年輕代 年輕代主要有三個區域組成,一個是Eden區域,另一個是存活區1和存活區2。Eden主要負責物件的建立,存活區1和存活2主要負責向老年代普及物件,存活區1和存活區2這兩個區域裡面總存在一個是空的,為什麼這兩個區域裡面有一個空的呢?因為這兩個區域需要負責回收年輕代活躍物件,需要把這些年輕

JVM年輕年代永久詳解

前言 最近被問到了這個問題,解釋的不是很清晰,有一些概念略微模糊,在此進行整理和記錄,分享給大家。本篇文章主要講解記憶體區域的年輕代,老年代和永久代,略微提及一些垃圾回收演算法,下面是正文。 堆整體 堆主要用於存放各種類的例項物件和陣列。在java中被分為兩個區域:年輕代和老年代。在java中還有一個永久

(入門貼)JVM記憶體相關的啟動引數:年輕年代和永久記憶體分配

如果想觀察JVM程序佔用的堆記憶體,可以通過命令工具jmap或者視覺化工具jvisualvm.exe。JVM這些啟動引數都擁有預設值,如果想了解JVM的記憶體分配策略,最好手動設定這些啟動引數。再通過

JVM內存:年輕年代、永久(推薦 轉)

回收 以及 平靜的 保持 size 個人 對象更新 you 應用 參考文章: 1.Java 新生代、老年代、持久代、元空間 2.Java內存與垃圾回收調優 3.方法區的Class信息,又稱為永久代,是否屬於Java堆? Java 中的堆是 JVM 所管理的最大的一塊內存空

GC日誌分析、年輕年代

堆記憶體 Java 中的堆是 JVM 所管理的最大的一塊記憶體空間,主要用於存放各種類的例項物件。 在 Java 中,堆被劃分成兩個不同的區域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被劃分為三個區域:Eden、From Sur

年輕年代、GC原理詳細拆解

1、為什麼要對堆記憶體分代     我們先來屢屢,為什麼需要把堆分代?不分代不能完成他所做的事情麼?其實不分代完全可以,分代的唯一理由就是優化GC效能。你先想想,如果沒有分代,那我們所有的物件都在一塊,GC的時候我們要找到哪些物件沒用,這樣就會對堆的所有區域進行掃描。而我們的

JVM的新生代和年代(Eden空間、兩個Survior空間)

現有的主流JVM分別是HotSpot和JRockit,主要研究物件也是這兩個。這篇文章裡,我們只研究HotSpot,也就是所謂的Sun JVM。目前階段,Sun的GC方式主要有CMS和G1兩種。考慮到效果和實際應用,這裡只介紹CMS。CMS,全稱Concurrent Low

java虛擬機器JVM--java虛擬機器的記憶體管理(新生代、年代

前言 在上一篇部落格中,還遺留了一個問題:JVM的記憶體如何分配最高效?換一種說法就是:JVM的記憶體是如何的分配以及回收的?通過前面兩篇部落格的鋪墊:java虛擬機器JVM–java虛擬機器的結構, java虛擬機器JVM–java虛擬機器垃圾的回收機制詳解

對這個java虛擬機器記憶體年輕年老永久i搞不太清楚。年輕、年老存放在堆還是棧。新版虛擬機器沒有永久是個啥情況

1.什麼是jvm?(1)jvm是一種用於計算裝置的規範,它是一個虛構出來的機器,是通過在實際的計算機上模擬模擬各種功能實現的。(2)jvm包含一套位元組碼指令集,一組暫存器,一個棧,一個垃圾回收堆和一個儲存方法域。(3)JVM遮蔽了與具體作業系統平臺相關的資訊,使Java

面試官Java8 JVM記憶體結構變了永久到元空間

在文章《JVM之記憶體結構詳解》中我們描述了Java7以前的JVM記憶體結構,但在Java8和以後版本中JVM的記憶體結構慢慢發生了變化。作為面試官如果你還不知道,那麼面試過程中是不是有些露怯?作為面試者,如果知曉這些變化,又將成為面試中的亮點。 如果在網路上搜索JVM記憶體結構,90%的可能會搜到Java7

的新生代與年代

垃圾回收 回收算法 init 掃描 什麽 gdi class 情況 tsp 1.為什麽會有年輕代 我們先來屢屢,為什麽需要把堆分代?不分代不能完成他所做的事情麽?其實不分代完全可以,分代的唯一理由就是優化GC性能。你先想想,如果沒有分代,那我們所有的對象都在一塊,GC的時候

JVM垃圾回收--年輕、年老點和持久

就會 為什麽 比例 生命 system 碎片 根據 請求 min 年輕代:   一般情況下,所有新生成的對象首先都是放在年輕代的。年輕代的目的就是盡可能快速的收集掉那些生命周期短的對象。年輕代分三個區。一個Eden區,兩個 Survivor區(分別叫from和to)Eden

JVM記憶體的堆疊、堆、方法區

堆疊、堆、方法區 JAVA的JVM的記憶體可分為3個區:堆(heap)、堆疊(stack)和方法區(method) 堆區:(例如:存放成員變數,又稱例項變數) 提供所有類例項和陣列物件儲存區域。 jvm只有一個堆區(heap)被所有執行緒共享,堆中不存放基本型別和物件引用,只

Java堆的新生代和年代以及相應的垃圾收集演算法

新生代 主要是用來存放新生的物件,會頻繁建立物件,所有垃圾收集會頻繁進行回收。在新生代中,每次垃圾收集時都發現有大批物件死去,只有少量存活,那就選用複製演算法,只需要付出少量存活物件的複製成本就可以完成收集。 複製演算法將記憶體分為三個區:一塊較大的Eden空間和兩塊較小的Su

JVM記憶體各部分存放的內容

虛擬機器記憶體中主要有程式計數器、虛擬機器棧、本地方法棧、堆和方法區。 程式計數器和虛擬機器棧都是執行緒“私有”的記憶體。 程式計數器是一塊比較下的記憶體空間,主要村放程式碼執行的位置。分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能都需要一來這個計數器來完成。 例如,多執行緒中,為了執

C/C++變數在記憶體的分佈堆疊區別堆疊段資料段程式碼段附加段

在C++中,記憶體分成5個區,他們分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區。 棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數、函式引數等。 堆,就是那些由new分配的記憶體塊,他們的釋放編譯器不

25、談談JVM記憶體區域的劃分哪些區域可能發生OutOfMemoryError?

目錄 今天我要問你的問題是,談談 JVM 記憶體區域的劃分,哪些區域可能發生 OutOfMemoryError? 典型回答 JAVA的JVM的3個區:堆(heap)、棧(stack)和方法區(method)  考點分析 知識擴充套件 接下來,我們來看看什麼是 OOM