




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Contanct Me如果覺(jué)得看起來(lái)比較麻煩,需要PDF版本,或是需要學(xué)習(xí)資料,都可以加上領(lǐng)取本群由我創(chuàng)立,目前已將群主權(quán)限交由合作方便于進(jìn)行日常管理,介意的朋友們?cè)谛掳婢秃昧松峡醋钸@份筆記資料是會(huì)提供的,特地向保證畢竟還是要恰飯的嘛祝愿每一位有追求的Java開發(fā)同胞都能進(jìn)大廠拿高薪! 號(hào):阿風(fēng)的架構(gòu)筆記回復(fù)【999】即可來(lái)獲取Java進(jìn)階面試筆記+學(xué)習(xí)腦圖Java內(nèi)存區(qū)域說(shuō)一下 JVM 的主要組成部分及其作用?JVM包含兩個(gè)子系統(tǒng)和兩個(gè)組件,兩個(gè)子系統(tǒng)為Class loader(類裝載)、Execution engine(執(zhí)行引擎);兩個(gè)組件為Runtime data area(運(yùn)行時(shí)數(shù)據(jù)區(qū)
2、)、Native Interface(本地接口)。Class loader(類裝載):根據(jù)給定的全限定名類名(如:java.lang.Object)來(lái)裝載class文件到Runtime data area中的method area。Execution engine(執(zhí)行引擎):執(zhí)行classes中的指令。Native Interface(本地接口):與native libraries交互,是其它編程語(yǔ)言交互的接口。Runtime data area(運(yùn)行時(shí)數(shù)據(jù)區(qū)域):這就是我們常說(shuō)的JVM的內(nèi)存。作用 :首先通過(guò)編譯器把 Java 代碼轉(zhuǎn)換成字節(jié)碼,類加載器(ClassLoader)再把字節(jié)碼
3、加載到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime data area)的方法區(qū)內(nèi),而字節(jié)碼文件只是 JVM 的一套指令集規(guī)范,并不能直接交給底層操作系統(tǒng)去執(zhí)行,因此需要特定令器執(zhí)行引擎(ExecutionEngine),將字節(jié)碼翻譯成底層系統(tǒng)指令,再交由 CPU 去執(zhí)行,而這個(gè)過(guò)程中需要調(diào)用其他語(yǔ)言的本地庫(kù)接口(Native Interface)來(lái)實(shí)現(xiàn)整個(gè)程序的功能。下面是Java程序運(yùn)行機(jī)制詳細(xì)說(shuō)明Java程序運(yùn)行機(jī)制步驟首先利用IDE集成開發(fā)工具編寫Java源代碼,源文件的后綴為.java;再利用編譯器(javac命令)將源代碼編譯成字節(jié)碼文件,字節(jié)碼文件的后綴名為.class; 運(yùn)行字
4、節(jié)碼的工作是由解釋器(java命令)來(lái)完成的。從上圖可以看,java文件通過(guò)編譯器變成了.class文件,接下來(lái)類加載器又將這些.class文件加載到JVM 中。其實(shí)可以一句話來(lái)解釋:類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行 時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個(gè) java.lang.Class對(duì)象,用來(lái)封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。說(shuō)一下 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)Java 虛擬機(jī)在執(zhí)行 Java 程序的過(guò)程中會(huì)把它所管理的內(nèi)存區(qū)域劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域。這些區(qū)域都有各自的用途,以及創(chuàng)建和銷毀的時(shí)間,有些區(qū)域隨著虛擬機(jī)進(jìn)程的啟動(dòng)而存在,有些區(qū)域則是依 賴線程的
5、啟動(dòng)和結(jié)束而建立和銷毀。Java 虛擬機(jī)所管理的內(nèi)存被劃分為如下幾個(gè)區(qū)域:不同虛擬機(jī)的運(yùn)行時(shí)數(shù)據(jù)區(qū)可能略微有所不同,但都會(huì)遵從 Java 虛擬機(jī)規(guī)范, Java 虛擬機(jī)規(guī)范規(guī)定的區(qū)域分為以下 5 個(gè)部分:程序計(jì)數(shù)器(Program Counter Register):當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器,字節(jié)碼器的工作是通過(guò)改變這個(gè)計(jì)數(shù)器的值,來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、 異常處理、線程恢復(fù)等基礎(chǔ)功能,都需要依賴這個(gè)計(jì)數(shù)器來(lái)完成;Java 虛擬機(jī)棧(Java Virtual Machine Stacks):用于法出口等信息;局部變量表、操作數(shù)棧、動(dòng)態(tài)、方本地方法棧(Nat
6、ive Method Stack):與虛擬機(jī)棧的作用是一樣的,只不過(guò)虛擬機(jī)棧是服務(wù) Java方法的,而本地方法棧是為虛擬機(jī)調(diào)用 Native 方法服務(wù)的;Java 堆(Java Heap):Java 虛擬機(jī)中內(nèi)存最大的一塊,是被所有線程共享的,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存;方法區(qū)(Methed Area):用于碼等數(shù)據(jù)。深拷貝和淺拷貝已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯后的代淺拷貝(shallowCopy)只是增加了一個(gè)指針指向已存在的內(nèi)存地址,深拷貝(deepCopy)是增加了一個(gè)指針并且申請(qǐng)了一個(gè)新的內(nèi)存,使這個(gè)增加的指針指向這個(gè)新的內(nèi)存,使用深拷貝的情況下,淺:僅僅是指
7、向被變。內(nèi)存的時(shí)候因?yàn)槌霈F(xiàn)淺拷貝時(shí)同一個(gè)內(nèi)存的錯(cuò)誤。的內(nèi)存地址,如果原地址發(fā)生改變,那么淺出來(lái)的對(duì)象也會(huì)相應(yīng)的改深:在計(jì)算機(jī)中開辟一塊新的內(nèi)存地址用于存放的對(duì)象。說(shuō)一下堆棧的區(qū)別?物理地址堆的物理地址分配對(duì)對(duì)象是不連續(xù)的。因此性能慢些。在GC的時(shí)候也要考慮到不連續(xù)的分配,所以有各種算法。比如,標(biāo)記-消除, 縮),標(biāo)記-壓縮,分代(即使用算法,老年代使用標(biāo)記壓棧使用的是數(shù)據(jù)結(jié)構(gòu)中的棧,先進(jìn)后出的原則,物理地址分配是連續(xù)的。所以性能快。內(nèi)存分別堆因?yàn)槭遣贿B續(xù)的,所以分配的內(nèi)存是在運(yùn)行期 確認(rèn)的,因此大小不固定。一般堆大小遠(yuǎn)遠(yuǎn)大于棧。棧是連續(xù)的,所以分配的內(nèi)存大小要在編譯期 就確認(rèn),大小是固定的。存
8、放的內(nèi)容堆存放的是對(duì)象的實(shí)例和數(shù)組。因此該區(qū)更關(guān)注的是數(shù)據(jù)的棧存放:局部變量,操作數(shù)棧,返回結(jié)果。該區(qū)更關(guān)注的是程序方法的執(zhí)行。PS:1. 靜態(tài)變量放在方法區(qū)2. 靜態(tài)的對(duì)象還是放在堆。程序的可見度堆對(duì)于整個(gè)應(yīng)用程序都是共享、可見的。棧只對(duì)于線程是可見的。所以也是線程私有。他的生命周期和線程相同。隊(duì)列和棧是什么?有什么區(qū)別?隊(duì)列和棧都是被用來(lái)預(yù)數(shù)據(jù)的。操作的名稱不同。隊(duì)列的出棧。稱為入隊(duì),隊(duì)列的刪除稱為出隊(duì)。棧的稱為進(jìn)棧,棧的刪除稱為可操作的方式不同。隊(duì)列是在隊(duì)尾入隊(duì),隊(duì)頭出隊(duì),即兩邊都可操作。而棧的進(jìn)棧和出棧都是在棧 頂進(jìn)行的,無(wú)法對(duì)棧底直接進(jìn)行操作。操作的方法不同。隊(duì)列是先進(jìn)先出(FIFO
9、),即隊(duì)列的修改是依先進(jìn)先出的原則進(jìn)行的。新來(lái)的成員總是加入隊(duì)尾(不能從中間),每次離開的成員總是隊(duì)列頭上(不中途離隊(duì))。而棧為后進(jìn)先出(LIFO),即每次刪除(出棧)的總是當(dāng)前棧中最新的元素,即最后(進(jìn)棧)的元素,而最先的被放在棧的底部,要到最后才能刪除。HotSpot虛擬機(jī)對(duì)象探秘對(duì)象的創(chuàng)建說(shuō)到對(duì)象的創(chuàng)建,首先讓我們看看 Java 中提供的幾種對(duì)象創(chuàng)建方式:下面是對(duì)象創(chuàng)建的主要流程:虛擬機(jī)遇到一條new指令時(shí),先檢查常量池是否已經(jīng)加載相應(yīng)的類,如果沒(méi)有,必須先執(zhí)行相應(yīng)的類加 載。類加載通過(guò)后,接下來(lái)分配內(nèi)存。若Java堆中內(nèi)存是絕對(duì)規(guī)整的,使用“指針碰撞“方式分配內(nèi)存;如果不是規(guī)整的,就從
10、空閑列表中分配,叫做”空閑列表“方式。劃分內(nèi)存時(shí)還需要考慮一個(gè)問(wèn)題-并發(fā),也 有兩種方式: CAS同步處理,或者本地線程分配緩沖(Thread Local Allocation Buffer, TLAB)。然后內(nèi)存空間初始化操作,接著是做一些必要的對(duì)象設(shè)置(元信息、哈希碼),最后執(zhí)行 <init> 方法。為對(duì)象分配內(nèi)存類加載完成后,接著會(huì)在Java堆中劃分一塊內(nèi)存分配給對(duì)象。內(nèi)存分配根據(jù)Java堆是否規(guī)整,有兩種方式:指針碰撞:如果Java堆的內(nèi)存是規(guī)整,即所有用過(guò)的內(nèi)存放在一邊,而空閑的的放在另一邊。分配內(nèi)存時(shí)將位于中間的指針指示器向空閑的內(nèi)存移動(dòng)一段與對(duì)象大小相等的距離,這樣便
11、完成分配內(nèi)存工作??臻e列表:如果Java堆的內(nèi)存不是規(guī)整的,則需要由虛擬機(jī)維護(hù)一個(gè)列表來(lái) 那些內(nèi)存是可用的,這樣在分配的時(shí)候可以從列表中 到足夠大的內(nèi)存分配給對(duì)象,并在分配后更新列表 。選擇哪種分配方式是由 Java 堆是否規(guī)整來(lái)決定的,而 Java 堆是否規(guī)整又由所采用的 收集器是否帶有壓縮整理功能決定。Header解釋使用new關(guān)鍵字調(diào)用了構(gòu)造函數(shù)使用Class的newInstance方法調(diào)用了構(gòu)造函數(shù)使用Constructor類的newInstance方法調(diào)用了構(gòu)造函數(shù)使用clone方法沒(méi)有調(diào)用構(gòu)造函數(shù)使用反序列化沒(méi)有調(diào)用構(gòu)造函數(shù)處理并發(fā)安全問(wèn)題對(duì)象的創(chuàng)建在虛擬機(jī)中是一個(gè)非常頻繁的行為,
12、哪怕只是修改一個(gè)指針?biāo)赶虻奈恢茫诓?況下也是不安全的,可能出現(xiàn)正在給對(duì)象 A 分配內(nèi)存,指針還沒(méi)來(lái)得及修改,對(duì)象 B 又同時(shí)使用了原來(lái)的指針來(lái)分配內(nèi)存的情況。解決這個(gè)問(wèn)題有兩種方案:對(duì)分配內(nèi)存空間的動(dòng)作進(jìn)行同步處理(采用 CAS + 失敗重試來(lái)保障更新操作的原子性);把內(nèi)存分配的動(dòng)作按照線程劃分在不同的空間之中進(jìn)行,即每個(gè)線程在 Java 堆中預(yù)先分配一小塊內(nèi)存,稱 地線程分配緩沖(Thread Local Allocation Buffer, TLAB)。哪個(gè)線程要分配內(nèi)存, 就在哪個(gè)線程的 TLAB 上分配。只有 TLAB 用完并分配新的 TLAB 時(shí),才需要同步鎖。通過(guò)-XX:+/-
13、 UserTLAB參數(shù)來(lái)設(shè)定虛擬機(jī)是否使用TLAB。對(duì)象的Java 程序需要通過(guò) JVM 棧上的現(xiàn)。目前主流的 方式有 句柄 和 直接指針 兩種方式。指針: 指向?qū)ο?,代表一個(gè)對(duì)象在內(nèi)存中的起始地址。句柄: 可以理解為指向指針的指針,維護(hù)著對(duì)象的指針。句柄不直接指向?qū)ο?,而是指向?qū)ο蟮闹羔槪ň浔话l(fā)生變化,指向固定內(nèi)存地址),再由對(duì)象的指針指向?qū)ο蟮恼鎸?shí)內(nèi)存地址。句柄Java 堆中劃分出一塊內(nèi)存來(lái)作為句柄池, 中 對(duì)象的句柄地址,而句柄中包含了對(duì)象實(shí)例數(shù)據(jù)與對(duì)象類型數(shù)據(jù)各自的具體地址信息,具體構(gòu)造如下圖所示:優(yōu)勢(shì): 中 的是穩(wěn)定的句柄地址,在對(duì)象被移動(dòng)( 收集時(shí)移動(dòng)對(duì)象是非常普遍的行為)時(shí)只會(huì)
14、改變句柄中的實(shí)例數(shù)據(jù)指針,而 本身不需要修改。直接指針如果使用直接指針 , 中 的直接就是對(duì)象地址,那么 Java 堆對(duì)象內(nèi)部的布局中就必須考慮如何放置 類型數(shù)據(jù)的相關(guān)信息。優(yōu)勢(shì):速度更快,節(jié)省了一次指針 的時(shí)間開銷。由于對(duì)象的 在 Java 中非常頻繁,因此這類開銷積少成多后也是非??捎^的執(zhí)行成本。HotSpot 中采用的就是這種方式。內(nèi)存溢出異常Java會(huì)存在內(nèi)存泄漏嗎?請(qǐng)簡(jiǎn)單描述內(nèi)存泄漏是指不再被使用的對(duì)象或者變量一直被占據(jù)在內(nèi)存中。理論上來(lái)說(shuō),Java是有GC 回收機(jī)制的,也就是說(shuō),不再被使用的對(duì)象,會(huì)被GC自動(dòng)回收掉,自動(dòng)從內(nèi)存中清除。但是,即使這樣,Java也還是存在著內(nèi)存泄漏的情
15、況,java導(dǎo)致內(nèi)存泄露的 很明確:長(zhǎng)生命周期的對(duì)象持有短生命周期對(duì)象的 就很可能發(fā)生內(nèi)存泄露,盡管短生命周期對(duì)象已經(jīng)不再需要,但是因?yàn)?長(zhǎng)生命周期對(duì)象持有它的 而導(dǎo)致不能被回收,這就是java中內(nèi)存泄露的發(fā)生場(chǎng)景。 收集器簡(jiǎn)述Java 回收機(jī)制在java中,程序員是不需要顯示的去 一個(gè)對(duì)象的內(nèi)存的,而是由虛擬機(jī)自行執(zhí)行。在JVM中,有一個(gè) 回收線程,它是低優(yōu)先級(jí)的,在正常情況下是 執(zhí)行的,只有在虛擬機(jī)空閑或者當(dāng)前堆內(nèi)存不足時(shí),才會(huì)觸發(fā)執(zhí)行,掃面那些沒(méi)有被任何 的對(duì)象,并將它們添加到要回收的集合中,進(jìn)行回收。GC是什么?為什么要GCGC 是 收集的意思(Gabage Collection),內(nèi)
16、存處理是編程 容易出現(xiàn)問(wèn)題的地方,忘記或者錯(cuò)誤的內(nèi)存回收會(huì)導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至 ,Java 提供的 GC 功能可以自動(dòng)監(jiān)測(cè)對(duì)象是否超過(guò)作用域從而達(dá)到自動(dòng)回收內(nèi)存的目的,Java 語(yǔ)言沒(méi)有提供 已分配內(nèi)存的顯示操作方法。回收的優(yōu)點(diǎn)和原理。并考慮2種回收機(jī)制java語(yǔ)言最顯著的特點(diǎn)就是引入了 回收機(jī)制,它使java程序員在編寫程序時(shí)不再考慮內(nèi)存管理的問(wèn)題。由于有這個(gè) 回收機(jī)制,java中的對(duì)象不再有“作用域”的概念,只有 的對(duì)象才有“作用域”?;厥諜C(jī)制有效的防止了內(nèi)存泄露,可以有效的使用可使用的內(nèi)存?;厥掌魍ǔW鳛橐粋€(gè)單獨(dú)的低級(jí)別的線程運(yùn)行,在不可預(yù)知的情況下對(duì)內(nèi)存堆中已經(jīng) 的或很長(zhǎng)時(shí)間沒(méi)有
17、用過(guò)的對(duì)象進(jìn)行清除和回收。程序員不能實(shí)時(shí)的對(duì)某個(gè)對(duì)象或所有對(duì)象調(diào)用 回收器進(jìn)行 回收?;厥沼蟹执厥掌鞯幕驹硎鞘裁?? 回收器可以馬上回收內(nèi)存嗎?有什么辦法主動(dòng)通知虛擬機(jī)進(jìn)行 回收?對(duì)于GC來(lái)說(shuō),當(dāng)程序員創(chuàng)建對(duì)象時(shí),GC就開始 這個(gè)對(duì)象的地址、大小以及使用情況。通常,GC采用有向圖的方式 和管理堆(heap)中的所有對(duì)象。通過(guò)這種方式確定哪些對(duì)象是"可達(dá)的",哪些對(duì)象是"不可達(dá)的"。當(dāng)GC確定一些對(duì)象為"不可達(dá)"時(shí),GC就有責(zé)任回收這些內(nèi)存空間。可以。程序員可以手動(dòng)執(zhí)行System.gc(),通知GC運(yùn)行,但是Java語(yǔ)言規(guī)范并不保
18、證GC一定會(huì)執(zhí)行。Java 中都有哪些 類型?強(qiáng) :發(fā)生 gc 的時(shí)候 被回收。軟 :有用但不是必須的對(duì)象,在發(fā)生內(nèi)存溢出之前會(huì)被回收。弱 :有用但不是必須的對(duì)象,在下一次GC時(shí)會(huì)被回收。虛 (虛 的用途是在 gc 時(shí)返回一個(gè)通知。怎么 對(duì)象是否可以被回收?收集器在做 回收的時(shí)候,首先需要判定的就是哪些內(nèi)存是需要被回收的,哪些對(duì)象是存活的,是不可以被回收的;哪些對(duì)象已經(jīng)死掉了,需要被回收。一般有兩種方法來(lái) :計(jì)數(shù)器法:為每個(gè)對(duì)象創(chuàng)建一個(gè) 計(jì)數(shù),有對(duì)象 時(shí)計(jì)數(shù)器 +1, 被 時(shí)計(jì)數(shù) -1, 當(dāng)計(jì)數(shù)器為 0 時(shí)就可以被回收。它有一個(gè)缺點(diǎn)不能解決循環(huán) 的問(wèn)題;可達(dá)性分析算法:從 GC Roots 開
19、始向下搜索,搜索所走過(guò)的路徑稱為 鏈。當(dāng)一個(gè)對(duì)象到 GC Roots 沒(méi)有任何 鏈相連時(shí),則證明此對(duì)象是可以被回收的。在Java中,對(duì)象什么時(shí)候可以被 回收當(dāng)對(duì)象對(duì)當(dāng)前使用這個(gè)對(duì)象的應(yīng)用程序變得不可觸及的時(shí)候,這個(gè)對(duì)象就可以被回收了?;厥?發(fā)生在 代,如果 代滿了或者是超過(guò)了臨界值,會(huì)觸發(fā)完全 回收(Full GC)。如果你仔細(xì)查看 收集器的輸出信息,就會(huì)發(fā)現(xiàn) 代也是被回收的。這就是為什么正確的 代大小對(duì)避免Full GC是非常重要的 。JVM中的 代中會(huì)發(fā)生 回收嗎回收 發(fā)生在 代,如果 代滿了或者是超過(guò)了臨界值,會(huì)觸發(fā)完全 回收(Full GC)。如果你仔細(xì)查看 收集器的輸出信息,就會(huì)發(fā)現(xiàn)
20、 代也是被回收的。這就是為什么正確的 代大小對(duì)避免Full GC是非常重要的 。請(qǐng)參考下Java8:從 代到元數(shù)據(jù)區(qū)(譯者注:Java8中已經(jīng)移除了 代,新加了一個(gè)叫做元數(shù)據(jù)區(qū)的native內(nèi)存區(qū))說(shuō)一下 JVM 有哪些 回收算法?標(biāo)記-清除算法:標(biāo)記無(wú)用對(duì)象,然后進(jìn)行清除回收。缺點(diǎn):效率不高,無(wú)法清除 碎片。算法:按照容量劃分二個(gè)大小相等的內(nèi)存區(qū)域,當(dāng)一塊用完的時(shí)候?qū)⒒钪膶?duì)象 到另一塊上,然后再把已使用的內(nèi)存空間一次 掉。缺點(diǎn):內(nèi)存使用率不高,只有原來(lái)的一半。標(biāo)記-整理算法:標(biāo)記無(wú)用對(duì)象,讓所有存活的對(duì)象都向一端移動(dòng),然后直接清除掉端邊界以外的內(nèi)存。分代算法:根據(jù)對(duì)象存活周期的不同將內(nèi)存劃
21、分為幾塊,一般是 和老年代, 基本采用算法,老年代采用標(biāo)記整理算法。標(biāo)記-清除算法 標(biāo)記無(wú)用對(duì)象,然后進(jìn)行清除回收。標(biāo)記-清除算法(Mark-Sweep)是一種常見的基礎(chǔ) 收集算法,它將 收集分為兩個(gè)階段: 標(biāo)記階段:標(biāo)記出可以回收的對(duì)象。清除階段:回收被標(biāo)記的對(duì)象所占用的空間。標(biāo)記-清除算法之所以是基礎(chǔ)的,是因?yàn)楹竺嬷v到的 收集算法都是在此算法的基礎(chǔ)上進(jìn)行改進(jìn)的。優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,不需要對(duì)象進(jìn)行移動(dòng)。缺點(diǎn):標(biāo)記、清除過(guò)程效率低,產(chǎn)生大量不連續(xù)的內(nèi)存碎片,提高了 回收的頻率。標(biāo)記-清除算法的執(zhí)行的過(guò)程如下圖所示算法為了解決標(biāo)記-清除算法的效率不高的問(wèn)題,產(chǎn)生了 算法。它把內(nèi)存空間劃為兩個(gè)相等的區(qū)
22、域,每次只使用其中一個(gè)區(qū)域。 收集時(shí),遍歷當(dāng)前使用的區(qū)域,把存活對(duì)象 到另外一個(gè)區(qū)域中,最后將當(dāng)前使用的區(qū)域的可回收的對(duì)象進(jìn)行回收。優(yōu)點(diǎn):按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單、運(yùn)行高效,不用考慮內(nèi)存碎片。缺點(diǎn):可用的內(nèi)存大小縮小為原來(lái)的一半,對(duì)象存活率高時(shí)會(huì)頻繁進(jìn)行 。算法的執(zhí)行過(guò)程如下圖所示標(biāo)記-整理算法在 中可以使用 算法,但是在老年代就不能選擇 算法了,因?yàn)槔夏甏膶?duì)象存活率會(huì)較高,這樣會(huì)有較多的 操作,導(dǎo)致效率變低。標(biāo)記-清除算法可以應(yīng)用在老年代中,但是它效率不高, 在內(nèi)存回收后容易產(chǎn)生大量?jī)?nèi)存碎片。因此就出現(xiàn)了一種標(biāo)記-整理算法(Mark-Compact)算法,與標(biāo)記-整理算法不同的是,在標(biāo)
23、記可回收的對(duì)象后將所有存活的對(duì)象壓縮到內(nèi)存的一端,使他們緊湊的排列在一起,然后對(duì)端邊界以外的內(nèi)存進(jìn)行回收?;厥蘸?,已用和未用的內(nèi)存都各自一邊。優(yōu)點(diǎn):解決了標(biāo)記- 算法存在的內(nèi)存碎片問(wèn)題。缺點(diǎn) 仍需要進(jìn)行局部對(duì)象移動(dòng), 定程度上降低了效率。標(biāo)記-整理算法的執(zhí)行過(guò)程如下圖所示分代收集算法當(dāng)前商業(yè)虛擬機(jī)都采用分代收集的收集算法。分代收集算法,顧名思義是根據(jù)對(duì)象的存活周期將內(nèi)存劃分為幾塊。一般包括年輕代、老年代 和代,:說(shuō)一下 JVM 有哪些回收器?如果說(shuō)收集算法是內(nèi)存回收的方法論,那么收集器就是內(nèi)存回收的具體實(shí)現(xiàn)。下圖展示了7種作用于不同分代的收集器,其中用于回收的收集器包括Serial、PraNe
24、w、Parallel Scavenge,回收老年代的收集器包括Serial Old、Parallel Old、CMS,還有用于回收整個(gè)Java堆的G1收集器。不同收集器之間的連線表示它們可以搭配使用。Serial收集器( ParNew收集器 (算法):算法):單線程收集器,標(biāo)記和都是單線程,優(yōu)點(diǎn)是簡(jiǎn)單高效;收并行集器,實(shí)際上是Serial收集器的多線程版本,在多核CPU環(huán)境下有著比Serial更好的表現(xiàn);Parallel Scavenge收集器 (算法):并行收集器,追求高吞吐量,高效利用 CPU。吞吐量= 用戶線程時(shí)間/(用戶線程時(shí)間+GC線程時(shí)間),高吞吐量可以高效率的利用CPU時(shí)間,盡快
25、完成程序的運(yùn)算任務(wù),適合應(yīng)用等對(duì)交互相應(yīng)要求不高的場(chǎng)景;Serial Old收集器 (標(biāo)記-整理算法): 老年代單線程收集器,Serial收集器的老年代版本;Parallel Old收集器 (標(biāo)記-整理算法): 老年代并行收集器,吞吐量?jī)?yōu)先,Parallel Scavenge收集器的老年代版本;CMS(Concurrent Mark Sweep)收集器(標(biāo)記-清除算法): 老年代并行收集器,以獲取最短回收停頓時(shí)間為目標(biāo)的收集器,具有高并發(fā)、低停頓的特點(diǎn),追求最短GC回收停頓時(shí)間。G1(Garbage First)收集器 (標(biāo)記-整理算法): Java堆并行收集器,G1收集器是JDK1.7提供的
26、一個(gè)新收集器,G1收集器基于“標(biāo)記-整理”算法實(shí)現(xiàn),也就是說(shuō)產(chǎn)生內(nèi)存碎片。此外,G1收集器不同于之前的收集器的一個(gè)重要特點(diǎn)是:G1回收的范圍是整個(gè)Java堆(包括,老年代),而前六種收集器回收的范圍僅限于詳細(xì)介紹一下 CMS或老年代?;厥掌鳎緾MS 是英文 Concurrent Mark-Sweep 的簡(jiǎn)稱,是以犧牲吞吐量為代價(jià)來(lái)獲得最短回收停頓時(shí)間的回收器。對(duì)于要求服務(wù)器響應(yīng)速度的應(yīng)用上,這種回收器非常適合。在啟動(dòng) JVM 的參數(shù)加上“-XX:+UseConcMarkSweepGC”來(lái)指定使用 CMS回收器。CMS 使用的是標(biāo)記-清除的算法實(shí)現(xiàn)的,所以在 gc 的時(shí)候回產(chǎn)生大量的內(nèi)存碎片,當(dāng)
27、剩余內(nèi)存不能滿足程序運(yùn)行要求時(shí),系統(tǒng)將會(huì)出現(xiàn) Concurrent Mode Failure,臨時(shí) CMS 會(huì)采用 Serial Old 回收器進(jìn)行垃圾清除,此時(shí)的性能將會(huì)被降低?;厥掌骱屠夏甏厥掌鞫加心男坑惺裁磪^(qū)別?回收器:Serial、ParNew、Parallel Scavenge老年代回收器:Serial Old、Parallel Old、CMS整堆回收器:G1收器一般采用的是標(biāo)記-整理的算法進(jìn)行回收。簡(jiǎn)述分代回收器是怎么工作的?分代回收器有兩個(gè)分區(qū):老生代和2/3。,默認(rèn)的空間占比總空間的 1/3,老生代的默認(rèn)占比是使用的是算法,里有 3 個(gè)分區(qū):Eden、To Survivor
28、、From Survivor,它們的默認(rèn)占比是 8:1:1,它的執(zhí)行流程如下:把 Eden + From Survivor 存活的對(duì)象放入 To Survivor 區(qū); 清空 Eden 和 From Survivor 分區(qū);From Survivor 和 To Survivor 分區(qū)交換,F(xiàn)rom Survivor 變 To Survivor,To Survivor 變 From Survivor。每次在 From Survivor 到 To Survivor 移動(dòng)時(shí)都存活的對(duì)象,15)時(shí),升級(jí)為老生代。大對(duì)象也會(huì)直接進(jìn)入老生代。就 +1,當(dāng)?shù)竭_(dá) 15(默認(rèn)配置是老生代當(dāng)空間占用到達(dá)某個(gè)值之后
29、就會(huì)觸發(fā)全局收回,一般使用標(biāo)記整理的執(zhí)行算法。以上這些循環(huán)往復(fù)就了整個(gè)分代回收的整體執(zhí)行流程。內(nèi)存分配策略簡(jiǎn)述java內(nèi)存分配與回收策率以及Minor GC和Major GC所謂自動(dòng)內(nèi)存管理,最終要解決的也就是內(nèi)存分配和內(nèi)存回收兩個(gè)問(wèn)題。前面我們介紹了內(nèi)存回收,這 里我們?cè)賮?lái)聊聊內(nèi)存分配。對(duì)象的內(nèi)存分配通常是在 Java 堆上分配(隨著虛擬機(jī)優(yōu)化技術(shù)的誕生,某些場(chǎng)景下也會(huì)在棧上分配,后面會(huì)詳細(xì)介紹),對(duì)象主要分配在的 Eden 區(qū),如果啟動(dòng)了本地線程緩沖,將按照線程優(yōu)先在TLAB 上分配。少數(shù)情況下也會(huì)直接在老年代上分配??偟膩?lái)說(shuō)分配規(guī)則不是百分百固定的,其細(xì)節(jié)取決于哪一種收集器組合以及虛擬機(jī)
30、相關(guān)參數(shù)有關(guān),但是虛擬機(jī)對(duì)于內(nèi)存的分配還是會(huì)遵循以下幾種規(guī)則:對(duì)象優(yōu)先在 Eden 區(qū)分配多數(shù)情況,對(duì)象都在Eden 區(qū)分配。當(dāng) Eden 區(qū)分配沒(méi)有足夠的空間進(jìn)行分配時(shí),虛擬機(jī)將會(huì)發(fā)起一次 Minor GC。如果本次 GC 后還是沒(méi)有足夠的空間,則將啟用分配擔(dān)保機(jī)制在老年代中分配內(nèi)存。這里我們提到 Minor GC,如果你仔細(xì)觀察過(guò) GC 日常,通常我們還能從日志中發(fā)現(xiàn) Major GC/Full GC。Minor GC 是指發(fā)生在的 GC,因?yàn)?Java 對(duì)象大多都是朝生夕死,所有 Minor GC 非常頻繁,一般回收速度也非??欤籑ajor GC/Full GC 是指發(fā)生在老年代的 GC
31、,出現(xiàn)了 Major GC 通常會(huì)伴隨至少一次 Minor GC。Major GC 的速度通常會(huì)比 Minor GC 慢 10 倍以上。大對(duì)象直接進(jìn)入老年代所謂大對(duì)象是指需要大量連續(xù)內(nèi)存空間的對(duì)象,頻繁出現(xiàn)大對(duì)象是致命的,會(huì)導(dǎo)致在內(nèi)存還有不少空間 的情況下提前觸發(fā) GC 以獲取足夠的連續(xù)空間來(lái)安置新對(duì)象。前面我們介紹過(guò)使用的是標(biāo)記-清除算法來(lái)處理回收的,如果大對(duì)象直接在分配就會(huì)導(dǎo)致 Eden 區(qū)和兩個(gè) Survivor 區(qū)之間發(fā)生大量的內(nèi)存。因此對(duì)于大對(duì)象都會(huì)直接在老年代進(jìn)行分配。長(zhǎng)期存活對(duì)象將進(jìn)入老年代虛擬機(jī)采用分代收集的思想來(lái)管理內(nèi)存,那么內(nèi)存回收時(shí)就必須象應(yīng)該放在老年代。因此虛擬機(jī)給每個(gè)
32、對(duì)象定義了一個(gè)對(duì)象哪些對(duì)象應(yīng)該放在,哪些對(duì)的計(jì)數(shù)器,如果對(duì)象在 Eden 區(qū)出生,并且能夠被 Survivor 容納,將被移動(dòng)到 Survivor 空間中,這時(shí)設(shè)置對(duì)象為 1。對(duì)象在 Survivor 區(qū)中每熬過(guò)一次 Minor GC就加 1,當(dāng)達(dá)到一定程度(默認(rèn) 15) 就會(huì)被晉升到老年代。虛擬機(jī)類加載機(jī)制簡(jiǎn)述java類加載機(jī)制?虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn), 擬機(jī)直接使用的java類型。描述一下JVM加載Class文件的原理機(jī)制和初始化,最終形成可以被虛Java中的所有類,都需要由類加載器裝載到JVM中才能運(yùn)行。類加載器本身也是一個(gè)類,而它的工作就是把c
33、lass文件從硬盤到內(nèi)存中。在寫程序的時(shí)候,我們幾乎不需要關(guān)心類的加載,因?yàn)檫@些都是隱式裝載的,除非我們有特殊的用法,像是反射,就需要顯式的加載所需要的類。類裝載方式,有兩種 :1. 隱式裝載, 程序在運(yùn)行過(guò)程中當(dāng)碰到通過(guò)new 等方式生成對(duì)象時(shí),隱式調(diào)用類裝載器加載對(duì)應(yīng)的類到j(luò)vm中,2. 顯式裝載, 通過(guò)class.forname()等方法,顯式加載需要的類Java類的加載是動(dòng)態(tài)的,它并基類)完全加載到j(luò)vm中,至于其他類,則在需要的時(shí)候才加載。這當(dāng)然就是為了節(jié)省內(nèi)存開銷。什么是類加載器,類加載器有哪些?實(shí)現(xiàn)通過(guò)類的權(quán)限定名獲取該類的二進(jìn)制字節(jié)流的代碼塊叫做類加載器。主要有一下四種類加載器
34、:1. 啟動(dòng)類加載器(Bootstrap ClassLoader)用來(lái)加載java類庫(kù),無(wú)法被java程序直接。2. 擴(kuò)展類加載器(extensions class loader):它用來(lái)加載 Java 的擴(kuò)展庫(kù)。Java 虛擬機(jī)的實(shí)現(xiàn)會(huì)提供一個(gè)擴(kuò)展庫(kù)目錄。該類加載器在此目錄里面查找并加載 Java 類。3. 系統(tǒng)類加載器(system class loader):它根據(jù) Java 應(yīng)用的類路徑(CLASSPATH)來(lái)加載 Java 類。一般來(lái)說(shuō),Java 應(yīng)用的類都是由它來(lái)完成加載的??梢酝ㄟ^(guò)ClassLoader.getSystemClassLoader()來(lái)獲取它。4. 用戶自定義類加載器,通過(guò)繼承 java.lang.ClassLoader類的方式實(shí)現(xiàn)。說(shuō)一下類裝載的執(zhí)行過(guò)程?類裝載分為以下 5 個(gè)步驟:加載:根據(jù)查找路徑找到相應(yīng)的 class 文件然后導(dǎo)入; 驗(yàn)證:檢查加載的 class 文件的正確性;準(zhǔn)備:給類中的靜態(tài)變量分配內(nèi)存空間;:虛擬機(jī)將常量池中的符號(hào)直接指向內(nèi)存中的地址;替換成直接的過(guò)程。符號(hào)就理解為一個(gè)標(biāo)示,而在直接初始化:對(duì)靜態(tài)變量和靜態(tài)代碼塊執(zhí)行初始化工作。什么
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 最美幼師活動(dòng)方案
- 智能文化拼圖活動(dòng)方案
- 暑期游樂(lè)園活動(dòng)方案
- 最后一公里文明活動(dòng)方案
- 智能家居狂歡節(jié)活動(dòng)方案
- 暑期探知課堂活動(dòng)方案
- 最美村長(zhǎng)評(píng)選活動(dòng)方案
- 曲藝系列活動(dòng)方案
- 機(jī)構(gòu)開館活動(dòng)方案
- 景區(qū)廟會(huì)預(yù)售活動(dòng)方案
- 《屹立在世界的東方》示范課教學(xué)課件【人教部編版小學(xué)道德與法治五年級(jí)下冊(cè)】
- 2023年音樂(lè)考試真題
- GB/T 16924-2008鋼件的淬火與回火
- 基礎(chǔ)護(hù)理學(xué):肌內(nèi)注射
- 應(yīng)急值守專題培訓(xùn)課件
- DB23T 1318-2020 黑龍江省建設(shè)施工現(xiàn)場(chǎng)安全生產(chǎn)標(biāo)準(zhǔn)化實(shí)施標(biāo)準(zhǔn)
- 新加坡公司法-英文版
- 醫(yī)院管理腎內(nèi)科腹膜透析護(hù)理常規(guī)
- 自動(dòng)控制原理浮球液位控制系統(tǒng)課程設(shè)計(jì)
- 離婚一方財(cái)產(chǎn)轉(zhuǎn)移
- 隧道施工安全技術(shù)教育培訓(xùn)記錄(共19頁(yè))
評(píng)論
0/150
提交評(píng)論