欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JVM的基本介紹以及垃圾回收

 更新時間:2021年09月08日 09:18:55   作者:傲嬌的喵醬  
垃圾回收(Garbage Collection,GC),顧名思義就是釋放垃圾占用的空間,防止內(nèi)存泄露,這篇文章主要給大家介紹了關(guān)于JVM垃圾回收的相關(guān)資料,需要的朋友可以參考下

JVM java虛擬機

JVM

java虛擬機是一個可執(zhí)行java字節(jié)碼的虛擬機進程。Java虛擬機本質(zhì)上就是一個程序,java源文件被編譯成能被java虛擬機執(zhí)行的字節(jié)碼文件,當它在命令行上啟動的時候,就開始執(zhí)行保存在某字節(jié)碼文件中的指令。Java語言的可移植性正是建立在Java虛擬機的基礎(chǔ)上。任何平臺只要裝有針對于該平臺的Java虛擬機,字節(jié)碼文件(.class)就可以在該平臺上運行。這就是“一次編譯,多次運行”。

java文件,通過編譯器變成了.class文件,接下來類加載器又將這些class文件加載到JVM中。其實可以一句話來解釋,類的加載指的是將類的.class文件二進制數(shù)據(jù)讀入到內(nèi)存中,將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),

然后在堆區(qū)創(chuàng)建一個 java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。

jvm主要組成部分及其作用

我們常說的jvm的主要組成,指的是運行時數(shù)據(jù)區(qū)。但是,其他它還包括其他部分,執(zhí)行引擎、本地接口、類加載子系統(tǒng)

 

jvm主要構(gòu)成:方法區(qū)、Java堆、Java虛擬機棧、本地方法區(qū)、程序計數(shù)器等。

JAVA Heap:堆,放的是new的對象,數(shù)組,大數(shù)據(jù)的東西;運行時的數(shù)據(jù)

JVM Stack: jvm棧,控制方法怎么調(diào)度,控制應(yīng)用程序怎么運行的

Native Method Stack:本地方法棧,本地的方法棧,調(diào)用本地服務(wù)

Method Area:方法區(qū),放的是運行時的方法

其中方法區(qū)和堆是由所有線程共享,

而Java棧、本地方法區(qū)、程序計數(shù)器是線程私有。

我們常說的內(nèi)存溢出,指的就是 java堆(Heap) 內(nèi)存不夠了。

JVM Stack jvm棧區(qū),每啟動個線程,jvm就為該線程分配一個棧區(qū),線程調(diào)用方法時和方法返回時進行入棧和出棧的操作。

Native Stack 本地方法棧區(qū),與jvm stack類似,不過此區(qū)域是為調(diào)用本地方法服務(wù)的

Java Heap java的所有對象實例,數(shù)組等。

程序計數(shù)寄存器 ,每個線程自己的計數(shù)寄存器,存儲當前線程執(zhí)行字節(jié)碼的地址。

Program Counter Register:程序計數(shù)器:

每個線程在創(chuàng)建后,都會產(chǎn)生自己的程序計數(shù)器和棧幀。程序計數(shù)器用來存放執(zhí)行指令的偏移量和行號指示器等。

線程執(zhí)行或者恢復(fù)都要依賴程序計數(shù)器。程序計數(shù)器在各個線程之間互不影響。此區(qū)域也不會發(fā)生內(nèi)存溢出異常,程序計數(shù)器是占用空間最小的內(nèi)存區(qū)域,不會出現(xiàn)OOM。

主要記錄當前線程正在執(zhí)行的方法的指令地址。方便線程切換后能恢復(fù)到下一條指令的位置,如果是執(zhí)行native方法,則該計數(shù)器為空。

程序計數(shù)器(后文簡稱PCR)有兩個作用:

  • 字節(jié)碼解釋器通過改變PCR依次讀取指令,實現(xiàn)代碼的流程控制,如順序執(zhí)行、選擇、循環(huán)、異常處理
  • 多線程情況下,PCR用于記錄當前線程的執(zhí)行位置,從而當線程被切換回來的時候,能夠知道該線程上次運行到哪兒了。

JVM Stack: jvm棧

java虛擬機棧也叫線程棧

虛擬機棧包含:

1、局部變量表

2、動態(tài)連接

3、操作棧

4、方法返回地址

1、局部變量表

存放方法參數(shù)和局部變量

相對于類屬性的變量準備階段和初始化階段,局部變量沒有準備階段,必需顯式初始化。

如果是非靜態(tài)方法,則在index[0]位置存儲的是方法所屬對象的實例引用,隨后存儲的是參數(shù)和局部變量。

2、動態(tài)連接

每個棧幀中包含一個在常量池中,對當前方法的引用。目的是支持方法調(diào)用過程的動態(tài)連接。

3、方法返回地址:

方法執(zhí)行的時候,有兩種退出情況:

正常退出

正常執(zhí)行到任何方法的返回字節(jié)碼指令,如RETURN、IRETURN等。

異常退出

無論何種,都將返回至方法當前被調(diào)用的位置。方法退出的過程相當于彈出當前棧幀。

3、操作棧

本地方法?;旧系韧趈ava虛擬機棧。

堆和棧是程序運行的關(guān)鍵,很有必要把他們癿關(guān)系說清楚。

棧是運行時的單位,而堆是存儲的單位。

棧解決程序的運行問題,即程序如何執(zhí)行,或者說如何處理數(shù)據(jù);

堆解決的是數(shù)據(jù)存儲的問題,即數(shù) 據(jù)怎么放、放在哪兒。

在 Java 中一個線程就會相應(yīng)有一個線程棧與之對應(yīng),這點很容易理解,因為不同的線程執(zhí)行邏輯有 所不同,因此需要一個獨立的線程棧。

而堆則是所有線程共享的。

棧因為是運行單位,因此里面存儲 的信息都是跟當前線程(或程序)相關(guān)信息的。包括局部變量、程序運行狀態(tài)、方法返回值等等;而 堆只負責存儲對象信息。

元數(shù)據(jù)區(qū)(Matespace):

包括:

常量池、類元信息、方法元信息

園區(qū)

JDK1.8之前叫持久代;1.8之后叫園區(qū)。

園區(qū)放的是方法常量

(以下非必需)

為什么要把堆和棧區(qū)分出來呢?棧中不是也可以存儲數(shù)據(jù)嗎?

第一,從軟件設(shè)計的角度看,棧代表了處理邏輯,而堆代表了數(shù)據(jù)。這樣分開,使得處理邏輯更為清 晰。分而治之的思想。這種隔離、模塊化的思想在軟件設(shè)計的方方面面都有體現(xiàn)。

第二,堆與棧的分離,使得堆中的內(nèi)容可以被多個棧共享(也可以理解為多個線程訪問同一個對象)。 這種共享的收益是很多的。一方面這種共享提供了一種有效的數(shù)據(jù)交互方式(如:共享內(nèi)存),另一方 面,堆中的共享常量和緩存可以被所有棧訪問,節(jié)省了空間。

第三,棧因為運行時的需要,比如保存系統(tǒng)運行的上下文,需要進行地址段的劃分。由于棧只能向上 增長,因此就會限制住棧存儲內(nèi)容的能力。而堆不同,堆中的對象是可以根據(jù)需要動態(tài)增長的,因此 棧與堆的拆分,使得動態(tài)增長成為可能,相應(yīng)棧中只需記錄堆中的一個地址即可。

第四,面向?qū)ο缶褪嵌雅c棧的完美結(jié)合。其實,面向?qū)ο蠓绞降某绦蚺c以前結(jié)構(gòu)化的程序在執(zhí)行上沒 有任何區(qū)別。但是,面向?qū)ο蟮囊?,使得對待問題的思考方式發(fā)生了改變,而更接近于自然方式的思考。

當我們把對象拆開,你會發(fā)現(xiàn),對象的屬性其實就是數(shù)據(jù),存放在堆中;而對象的行為(方法), 就是運行邏輯,放在棧中。

我們在編寫對象的時候,其實即編寫了數(shù)據(jù)結(jié)構(gòu),也編寫了處理數(shù)據(jù)的邏輯。

在 Java 中,Main 函數(shù)就是棧的起始點,也是程序的起始點。

程序要運行總是有一個起點的。同 C 語言一樣,java 中的 Main 就是那個起點。無論什么java 程序, 找到 main 就找到了程序執(zhí)行的入口:

堆:

運行時的數(shù)據(jù),也就是new的對象和一些數(shù)組。

運行時最大的數(shù)據(jù),就在堆內(nèi)。

Jvm heap內(nèi)存空間劃分

堆內(nèi)(放的是對象,數(shù)組)=臨時數(shù)據(jù),用完就沒啦

年輕代:eden +s1 +s0(eden:s1 :s0默認比例:8:1:1 )

老年代:(年輕代:老年代默認比例:1:2)

s0與s1大小相等,位置互換

堆外(放的是方法,類,常量)

Eden(伊甸園區(qū)):

所有新new的對象和數(shù)組,是在伊甸園區(qū)產(chǎn)生的,內(nèi)存分配是在伊甸園區(qū)進行的。

在伊甸園區(qū)new 一個對象,如果這個對象被用到了,那么他的引用就+1。應(yīng)用的越多,占內(nèi)存越多。

當伊甸園區(qū)內(nèi)存被占滿時,就不能再new對象,程序依賴對象,所以程序也就不能運行。java應(yīng)用程序為了能繼續(xù)運行,就要干掉那些不被引用的對象,對這些不被引用的對象進行垃圾回收。

現(xiàn)代虛擬機一般使用的內(nèi)存回收策略是分代收集,即把對象分為兩代,新生代(年輕代)使用復(fù)制算法回收內(nèi)存,老年代使用標志-整理算方法回收內(nèi)存。

垃圾回收的時候,如何判斷該對象是否可以被回收:

有2種算法

算法一:引用計數(shù)(已經(jīng)被廢棄了)

引用計數(shù),對象被創(chuàng)建后,有個計數(shù)器。只要對象被引用,那么計數(shù)器就+1,再次被引用,就再+1,如果方法執(zhí)行完成,對象不被引用了,計數(shù)器就-1。

當計數(shù)器為0時,該對象沒有被引用,就可以被垃圾回收了。

引用計數(shù)算法,有一個弊端,就是在執(zhí)行遞歸的時候,就沒有辦法計算了。

算法二:尋根判斷

尋根判斷,從對象的根結(jié)點開始去找,是否被引用,如果跟節(jié)點都沒有引用,那么就是沒有被引用。

被引用的對象,稱為存活對象。

未被引用的對象,稱為非存活對象。

當伊甸園區(qū)被占滿時,觸發(fā)GC(垃圾回收 Garbage Collection)。

GC分兩步,第1步標記,對非存活對象進行標記。第2步清掃,將非存活對象從內(nèi)存中干掉,釋放內(nèi)存,同時將存活的對象移到存活區(qū)中。

YGC

發(fā)生在年輕代。

在YGC之前,伊甸園區(qū)是滿的,無法new對象,程序無法運行。

YGC之后,伊甸園區(qū)就空了,就可以繼續(xù)new對象。

YGC整個流程:

第一次gc,,對存活的對象進行標記,然后將Eden區(qū)的存活對象,存活區(qū)S0

第二次gc,使用尋根判斷的算法,對存活的對象進行標記,然后將Eden區(qū)的存活對象,移到存活區(qū)S0

步驟1:new的對象、數(shù)組,直接進入eden園區(qū)。

步驟2:eden園區(qū)滿了,觸發(fā)ygc,對【eden園區(qū)】的對象和數(shù)組進行標記(使用尋根判斷的算法),清掃(將沒有引用的對象干掉,被引用的移到其中一個存活區(qū)s0);

eden園區(qū)第二次滿了,再次觸發(fā)ygc,對【eden園區(qū)和存活區(qū)s0】的對象和數(shù)組進行標記,清掃將沒有引用的干掉,被引用的對象和數(shù)組移到在另一個存活區(qū)s1(這里用的是復(fù)制算法)

步驟3:fgc,全gc,堆內(nèi)存和持久代均gc。將沒有的干掉,有用的放到老年代。

年輕代里面的兩個存活區(qū),大小相等,且同一時間只有一個存活區(qū)有對象,另一個存活區(qū)為空。gc之前,存活區(qū)s0有對象,s1為空,一次gc之后,s0為空,s1存放對象。

對象進入老年代原則:

大對象直接進入老年代長期存活的對象進入老年代動態(tài)年齡判斷一次Young GC時數(shù)據(jù)放到存活區(qū),但是存活區(qū)滿了導(dǎo)致放不下去此時直接進入老年代(盡可能避免這種情況)

1、大對象直接進入老年代

在堆中分配的大對象直接挪到老年代

大對象是指需要大量連續(xù)內(nèi)存空間的對象,例如很長的字符串以及數(shù)組。

虛擬機設(shè)置了一個-XX:PretenureSizeThreshold參數(shù),有個默認值,令大于這個設(shè)置的對象直接在老年代分配,這個值是可以修改的。

目的就是為了防止大對象在Eden空間和Survivor空間來回大量復(fù)制,大對象很容易把伊甸園區(qū)占滿,導(dǎo)致YGC頻繁。

2、長期存活的對象進入老年代(伴隨YGC產(chǎn)生的)

虛擬機給每個對象定義了一個對象年齡(Age)計數(shù)器,如果對象在Eden區(qū)出生并經(jīng)過第一次YGC/Mintor GC后仍然存活,并且能被Survivor接納,并被移動到Survivor空間上,那么該對象年齡將被設(shè)置為1。

對象在Survivor區(qū)中每熬過一次YGC/Minor GC,年齡就加一,當他的年齡增加到一定程度,就會被移動到老年代(年齡值默認為15)。

對象晉升老年代的閾值可以通過-XX:MaxTenuringThreshold設(shè)置。

3、動態(tài)年齡判斷并進入老年代(伴隨YGC產(chǎn)生的)

為了更好的適應(yīng)不同程序的內(nèi)存狀況,虛擬機并不是永遠要求對象的年齡必須達到MaxTenuringThreshold才會晉升到老年代。

如果在Survivor空間中相同年齡的所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進入老年代,無需達到MaxTensuringThreshold的要求年齡。

(相同age對象大小之和>1/2存活區(qū)(即s0或者s1)則所有>=age的對象就會進入老年代)

舉個栗子:

比如:MaxTenuringThreshold 為15,Survivor內(nèi)存大小為100M。age 為1的,所有對象大小之和為10M。age 為5的,所有對象大小之和為51M。age為6的,所有對象大小之和為5M.

因為age 為5的對象所占內(nèi)存之和已經(jīng)超過了Survivor空間的一半,所以age為5,和age大于5的對象,都要移到老年代(沒有age達到15的限制)

4、一次Young GC時數(shù)據(jù)放到存活區(qū),但是存活區(qū)滿了導(dǎo)致放不下去此時直接進入老年代

盡可能避免這種情況,如果對象直接從Eden區(qū)到老年代,那么存活區(qū)就沒有什么存在的意義了,之所以設(shè)置存活區(qū),就是為了將沒有引用的對象更早的回收掉,將內(nèi)存騰出來。

Full GC

當老年代滿了之后,觸發(fā)Full GC。

Full GC 范圍:

整個堆內(nèi)存(年輕代+老年代)+園數(shù)據(jù)區(qū)

對堆的回收:

標記--清掃

對堆標記,對象是否被引,被引用的為存活對象。

對園數(shù)據(jù)回收:

標記--清掃

標記類,哪些類失效了。

回收,將失效的類卸載掉。

FGC時長,大小跟內(nèi)存大小有關(guān)系,內(nèi)存大,則FGC時間長。

時長不太好控制,但是我們可以控制FGC頻次。

當老年代和年輕代,被存活的對象占滿時(GC也不能將這些存活的對象清理掉),在Eden就不能再創(chuàng)建新的對象,導(dǎo)致OOM。

http://www.itcdns.cn/skill/detail/1586233667857

一、OOM含義:

OOM,全稱“Out Of Memory”,意思是“內(nèi)存用完了”。 它來源于java.lang.OutOfMemoryError。

官方介紹為當JVM因為沒有足夠的內(nèi)存來為對象分配空間并且垃圾回收器也已經(jīng)沒有空間可回收時,就會拋出 java.lang.OutOfMemoryError :···

(注意:這是個很嚴重的問題,因為這個問題已經(jīng)嚴重到不足以被應(yīng)用處理)。 

gc的觸發(fā)條件

觸發(fā)條件:

YGC:

有且只有這一種情況,eden滿了,觸發(fā)gc

FGC:

1、老年代滿了

2、園區(qū)某些類已經(jīng)失效了,在加載的找不到這個類,也會觸發(fā)FGC,去卸載這個類,釋放這個類。

3、空間擔保原則(主要觸發(fā)fgc的方式)

4、代碼里面顯示調(diào)用

5、jmap dump

內(nèi)存擔保機制

現(xiàn)代虛擬機把新生代分為三個區(qū)域,一個Eden區(qū)域,兩個Survivor區(qū)域,Eden區(qū)域與Survivor區(qū)域的比例大小是8:1,虛擬機在YGC/Minor GC時在新生代采用復(fù)制算法,將存活對象復(fù)制到一個Survivor上面,如果Survivor空間不夠用時,就需要老年代進行分配擔保。

在發(fā)生Minor GC之前虛擬機會先檢查老年代最大可用的連續(xù)空間是否大于新生代對象的總空間。如果這個條件成立,那么Minor GC可以確保是安全的。如果不成立,虛擬機會查看HandlePromotionFailure設(shè)置值是否允許擔保失敗。如果允許,虛擬機會繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代的平均年齡(因為事先不知道存活對象的內(nèi)存空間,所以取了平均值)。若果大于,虛擬機會嘗試進行一次Minor GC,但是這次Minor GC存在風(fēng)險。如果小于,或者HandlePromotionFailure不允許擔保,那這次也要改為Full GC

空間擔保原則:

每次ygc的時候,都會往老年代里放對象。

根據(jù)歷史每次往老年代放的對象大小,根據(jù)一個算法,估算這一次要放對象大小。估算的數(shù)值,小于老年代剩余內(nèi)存,就執(zhí)行ygc。

如果大于老年代剩余空間,放棄本次ygc,直接fgc。

代碼里面顯示調(diào)用

代碼里寫了system.gc或者get run time .gc

fgc特別消耗cpu,盡可能把FGC頻次減少,最起碼要一小時以上

java進程之間以及跟JVM是什么關(guān)系

1.程序的運行是以進程在內(nèi)存中的運行形式體現(xiàn)的。當你啟動一個程序時,系統(tǒng)會調(diào)用其對應(yīng)進程進入內(nèi)存運行,圖中進程的pid即為進程的唯一標識符。然后進程之間是并發(fā)執(zhí)行的。準確的說,你啟動的是java程序,但系統(tǒng)運行的是進程,因為程序是靜態(tài)的,進程才是動態(tài)的,也就是程序并不會進入內(nèi)存運行,而是其對應(yīng)進程進入內(nèi)存運行。

2.是公用一個JVM的,這個就類似你電腦自己的操作系統(tǒng),打開兩個程序肯定是在同一個系統(tǒng)內(nèi)存中運行的,原因就是我問題一中說的進程是并發(fā)執(zhí)行的。

命令行啟動的java程序是共用一個jvm的,啟動一個程序就是在jvm中開啟一個進程,每個進程至少有一個線程,當然可以有多個線程,

線程之間通信比較簡單,就像java書上講的一樣,但進程間的通信復(fù)雜點,如管道、內(nèi)存映射、內(nèi)存共享、消息隊列、socket等,你可以簡單理解為兩個進程間沒關(guān)系

2個進程肯定是2個jvm實例

二、監(jiān)控GC命令

1、jstat監(jiān)控Java進程的GC情況

登陸服務(wù)器

ssh root@47.95.122.13

查看java進程

ps -ef|grep java

監(jiān)控fgc次數(shù)和時間

jstat -gcutil 22893 2000

jstat  -gcutil  [Java的pid] 2000 20 (間隔2s,總共打印20次)

jstat -gcutil 22278 2000

查看gc的情況(內(nèi)存使用百分比及gc的總時間,gc次數(shù))

總結(jié)

到此這篇關(guān)于JVM的基本介紹以及垃圾回收的文章就介紹到這了,更多相關(guān)JVM垃圾回收內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring框架生成圖片驗證碼實例

    Spring框架生成圖片驗證碼實例

    驗證碼在很多地方都會遇到,實現(xiàn)的方法和形式也有很多,主要的目的就是為了安全,防止一些惡意的攻擊等。今天在之前搭建好的一個spring框架上寫了一個驗證碼的生成demo,我會貼出細節(jié)代碼,但是spring的配置就不在介紹了,有需要的可以參考借鑒。
    2016-08-08
  • Jmeter線程組傳參原理解析

    Jmeter線程組傳參原理解析

    這篇文章主要介紹了jmeter線程組傳參原理解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • spring?@Transactional注解中常用參數(shù)詳解

    spring?@Transactional注解中常用參數(shù)詳解

    這篇文章主要介紹了spring?@Transactional注解中常用參數(shù)詳解,事物注解方式:?@Transactional,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2024-02-02
  • springboot整合netty框架的方式小結(jié)

    springboot整合netty框架的方式小結(jié)

    Netty 是一個基于NIO的客戶、服務(wù)器端編程框架,使用Netty 可以確保你快速和簡單的開發(fā)出一個網(wǎng)絡(luò)應(yīng)用,這篇文章主要介紹了springboot整合netty框架的方式小結(jié),需要的朋友可以參考下
    2022-06-06
  • Java中一維二維數(shù)組的靜態(tài)和動態(tài)初始化

    Java中一維二維數(shù)組的靜態(tài)和動態(tài)初始化

    今天通過本文給大家分享Java中的數(shù)組,包括一維數(shù)組和二維數(shù)組的靜態(tài)初始化和動態(tài)初始化問題,感興趣的朋友一起看看吧
    2017-10-10
  • 介紹Jersey-Jersey入門基礎(chǔ)

    介紹Jersey-Jersey入門基礎(chǔ)

    REST不是一種新的技術(shù),而僅僅是一個理論,實踐這樣的理論可以讓我們的應(yīng)用更加先進。
    2013-02-02
  • Java文件復(fù)制多種方法實例代碼

    Java文件復(fù)制多種方法實例代碼

    近期用到文件復(fù)制,雖然程序很簡單,因為時間久了淡忘了,所以寫一篇文章記錄一下,下面這篇文章主要給大家介紹了關(guān)于Java文件復(fù)制多種方法的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-05-05
  • java進制轉(zhuǎn)換工具類實現(xiàn)減少參數(shù)長度

    java進制轉(zhuǎn)換工具類實現(xiàn)減少參數(shù)長度

    這篇文章主要為大家介紹了java進制轉(zhuǎn)換工具類實現(xiàn)減少參數(shù)長度示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Java+Redis撤銷重做功能實現(xiàn)

    Java+Redis撤銷重做功能實現(xiàn)

    這篇文章主要介紹了Java+Redis實現(xiàn)撤銷重做功能,需要考慮撤銷的最大步數(shù),撤銷之后穿插著其他操作則不能再重做,所以引入分布式鎖Redisson進行加鎖處理,防止對圖表的操作有并發(fā)請求導(dǎo)致處理撤銷邏輯混亂,感興趣的朋友跟隨小編一起看看吧
    2023-05-05
  • Mybatis調(diào)用存儲過程的案例

    Mybatis調(diào)用存儲過程的案例

    這篇文章主要介紹了Mybatis如何調(diào)用存儲過程,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07

最新評論