JVM中常見面試題

介紹JVM中7個區(qū)域,然后把每個區(qū)域可能造成內(nèi)存的溢出的情況說明

程序計數(shù)器:看做當前線程所執(zhí)行的字節(jié)碼行號指示器。是線程私有的內(nèi)存,且唯一一塊不報OutOfMemoryError異常。Java虛擬機棧:用于描述java方法的內(nèi)存模型:每個方法被執(zhí)行時都會同時創(chuàng)建一個棧幀用于存儲局部變量表,操作數(shù)棧,動態(tài)鏈接,方法出口等信息。每一個方法被調(diào)用直至執(zhí)行完成的過程就對應(yīng)著一個棧幀在虛擬機中從入棧到出棧的過程。如果線程請求的棧深度大于虛擬機所允許的深度就報StackOverflowError, 如果虛擬機??梢詣討B(tài)擴展,當拓展時無法申請到足夠的內(nèi)存會拋出OutOfMemoryError. 是線程私有的。本地方法棧:與虛擬機棧相似,不同的在于它是為虛擬機使用到的Native方法服務(wù)的。會拋出StackOverflowError和OutOfMemoryError。是線程私有的。Java堆:是所有線程共享的一塊內(nèi)存,在虛擬機啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內(nèi)存。如果堆上沒有內(nèi)存完成實例的分配就會報OutOfMemoryError.方法區(qū)(永久代):用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。當方法區(qū)無法滿足內(nèi)存分配需求時,會拋出OutOfMemoryError。是共享內(nèi)存。運行時常量池:用于存放編譯器生成的各種字面量和符號引用,是方法區(qū)的一部分。無法申請內(nèi)存時拋出OutOfMemoryError。直接內(nèi)存:不是虛擬機運行時數(shù)據(jù)的一部分,也不是java虛擬機規(guī)范中定義的區(qū)域,是計算機直接的內(nèi)存空間。這部分也被頻繁使用,如JAVA NIO的引入基于通道和緩存區(qū)的I/O使用native函數(shù)直接分配堆外內(nèi)存。如果內(nèi)存不足會報OutOfMemoryError。

GC的兩種判定方法:引用計數(shù)與根搜索算法。引用計數(shù): 給對象添加一個引用計數(shù)器,每當有一個地方引用該對象時,計數(shù)器值加1,當引用失效時,計數(shù)器值減1,。任何時候計數(shù)器都為0的對象就是不可能再被使用的。它很難解決對象之間相互循環(huán)引用問題。根搜索算法(GC Roots Traceing):通過一系列名為“GC Roots”的對象作為起點,從這些節(jié)點開始向下搜索,搜索走過的路徑成為引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象不可用。 GC Roots對象一般是:虛擬機棧中的引用對象,方法區(qū)中類靜態(tài)屬性引用的對象,方法區(qū)常量引用的對象等。

Java中的四種引用

強引用:程序代碼中的普通引用。如Object obj = new Object(),只要強引用存在,垃圾回收器就不會回收。軟引用:描述一些有用但并非必須的對象。對于軟引用關(guān)聯(lián)的對象在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會把這些對象列進回收范圍之中進行第二次回收。SoftRefence弱引用:描述非必須對象,比軟引用弱一些。被弱引用關(guān)聯(lián)的對象只能生存到下一次垃圾收集發(fā)生之前。無論當前內(nèi)存是否足夠,都會回收掉只被弱引用關(guān)聯(lián)的對象。WeakRefence虛引用:最弱的引用,不管是否有虛引用存在,完全不會對對象生存時間構(gòu)成影響,也無法通過虛引用來取得一個對象實例。唯一目的是希望能夠在這個對象被垃圾回收器之前收到系統(tǒng)通知。PhantomReference

對象創(chuàng)建方法,對象的內(nèi)存分配,對象的訪問定位。

Object obj = new Object(); obj 保存在java棧中的局部變量表里,作為一個引用數(shù)據(jù)出現(xiàn)。 New Object()會在java堆上分配一塊存儲Object類型實例的所有數(shù)值的結(jié)構(gòu)化內(nèi)存,根據(jù)類型以及虛擬機實現(xiàn)的對象內(nèi)存布局不同。這塊內(nèi)存是不固定的。 對象訪問方式有兩種:句柄和直接指針:句柄:在java堆中會劃分出一塊內(nèi)存作為句柄池,reference中存儲的對象是句柄地址。而句柄中包含對象實例數(shù)據(jù)和類型數(shù)據(jù)各自的具體地址信息。最大的好處是如果對象地址發(fā)生變化不需要改變reference的值,只需要改變句柄中實例數(shù)據(jù)指針。直接指針訪問:reference直接存儲對象的地址,最大的好處是速度更快。

內(nèi)存溢出和內(nèi)存泄漏

內(nèi)存溢出:通俗理解就是內(nèi)存不夠,程序所需要的內(nèi)存遠遠超出了你虛擬機分配的內(nèi)存大小,就叫內(nèi)存溢出內(nèi)存泄露:內(nèi)存泄漏也稱作“存儲滲漏”,用動態(tài)存儲分配函數(shù)動態(tài)開辟的空間,在使用完畢后未釋放,結(jié)果導致一直占據(jù)該內(nèi)存單元。直到程序結(jié)束。(其實說白了就是該內(nèi)存空間使用完畢之后未回收)即所謂內(nèi)存泄漏

內(nèi)存溢出了怎么辦

通過內(nèi)存映像工具如jhat,jconsole等對dump出來的堆轉(zhuǎn)存儲快照進行分析,重點是確認內(nèi)存是出現(xiàn)內(nèi)存泄露還是內(nèi)存溢出。 如果是內(nèi)存泄露進一步使用工具查看泄露的對象到GC Roots的引用鏈。于是就能找到泄露對象是通過怎樣的路徑與GC Roots相關(guān)聯(lián)并導致垃圾收集器無法自動回收它們。掌握泄露對象的信息,以及GC Roots引用鏈的信息,就可以比較準確定位泄露代碼的位置。 如果不存在**內(nèi)存泄露,那就需要通過jinfo,Jconsole等工具分析java堆參數(shù)與機器物理內(nèi)存對比是否還可以調(diào)大,從代碼上檢查是否存在某些對象生命周期過長,持有狀態(tài)過長的情況,嘗試減少程序的運行消耗。

Java 中有內(nèi)存泄露嗎?

有,Java中,造成內(nèi)存泄露的原因有很多種。典型的例子是長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內(nèi)存泄露,盡管短生命周期對象已經(jīng)不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收,這就是java中內(nèi)存泄露的發(fā)生場景,通俗地說,就是程序員可能創(chuàng)建了一個對象,以后一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是java中可能出現(xiàn)內(nèi)存泄露的情況,例如,緩存系統(tǒng),我們加載了一個對象放在緩存中(例如放在一個全局map對象中),然后一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。 檢查java中的內(nèi)存泄露,一定要讓程序?qū)⒏鞣N分支情況都完整執(zhí)行到程序結(jié)束,然后看某個對象是否被使用過,如果沒有,則才能判定這個對象屬于內(nèi)存泄露。(采用什么工具?)如果一個外部類的實例對象的方法返回了一個內(nèi)部類的實例對象,這個內(nèi)部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由于內(nèi)部類持久外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內(nèi)存泄露。http://www.mamicode.com/info-detail-504269.html

什么時候會發(fā)生jvm堆(持久區(qū))內(nèi)存溢出

簡單的來說 java的堆內(nèi)存分為兩塊:permantspace(持久代) 和 heap space。 持久帶中主要存放用于存放靜態(tài)類型數(shù)據(jù),如 Java Class, Method 等, 與垃圾收集器要收集的Java對象關(guān)系不大。 而heapspace分為年輕代和年老代 年輕代的垃圾回收叫 Young GC, 年老代的垃圾回收叫 Full GC。 在年輕代中經(jīng)歷了N次(可配置)垃圾回收后仍然存活的對象,就會被復制到年老代中。因此,可以認為年老代中存放的都是一些生命周期較長的對象 年老代溢出原因有 循環(huán)上萬次的字符串處理、創(chuàng)建上千萬個對象、在一段代碼內(nèi)申請上百M甚至上G的內(nèi)存 持久代溢出原因動態(tài)加載了大量Java類而導致溢出,以及生產(chǎn)大量的常量。永久代內(nèi)存泄露: 以一個部署到應(yīng)用程序服務(wù)器的Java web程序來說,當該應(yīng)用程序被卸載的時候,你的EAR/WAR包中的所有類都將變得無用。只要應(yīng)用程序服務(wù)器還活著,JVM將繼續(xù)運行,但是一大堆的類定義將不再使用,理應(yīng)將它們從永久代(PermGen)中移除。如果不移除的話,我們在永久代(PermGen)區(qū)域就會有內(nèi)存泄漏。

堆里面的分區(qū):Eden,survival from to,老年代,各自的特點。

新生代:朝生夕死 老年代一般是放對象和長期存活對象。當一個對象分配的內(nèi)存空間大于某個閾值時或則年齡增加到一定程度(默認15歲)就進入老年代。

OOM你遇到過哪些情況

java.lang.OutOfMemoryError: Java heap space ------>java堆內(nèi)存溢出,此種情況最常見,一般由于內(nèi)存泄露或者堆的大小設(shè)置不當引起。 java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即方法區(qū)溢出了,一般出現(xiàn)于大量Class或者jsp頁面,或者采用cglib等反射機制的情況,因為上述情況會產(chǎn)生大量的Class信息存儲于方法區(qū)。 java.lang.StackOverflowError ------> 不會拋OOM error,但也是比較常見的Java內(nèi)存溢出。JAVA虛擬機棧溢出,一般是由于程序中存在死循環(huán)或者深度遞歸調(diào)用造成的,棧大小設(shè)置太小也會出現(xiàn)此種溢出??梢酝ㄟ^虛擬機參數(shù)-Xss來設(shè)置棧的大小。

GC的三種收集方法:標記清除、標記整理、復制算法的原理與特點,分別用在什么地方,如果讓你優(yōu)化收集方法,有什么思路?

標記清理:首先標記所有需要回收的對象,在標記完成后統(tǒng)一回收掉所有被標記的對象,它的標記的對象。缺點是效率低,且存在內(nèi)存碎片。主要用于老生代垃圾回收。復制算法:將內(nèi)存按容量劃分為大小相等的一塊,每次只用其中一塊。當內(nèi)存用完了,將還存活的對象復制到另一塊內(nèi)存,然后把已使用過的內(nèi)存空間一次清理掉。實現(xiàn)簡單,高效。一般用于新生代。一般是將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間。HotSpot虛擬機默認比例是8:1,。每次使用Eden和一塊Survivor,當回收時將這兩塊內(nèi)存中還存活的對象復制到Survivor然后清理掉剛才Eden和Survivor的空間。如果復制過程內(nèi)存不夠使用則向老年代分配擔保。標記整理:首先標記所有需要回收的對象,在標記完成后讓所有存活的對象都向一端移動,然后直接清理掉端邊界意外的內(nèi)存。用于老年代。分代收集算法:根據(jù)對象的生存周期將內(nèi)存劃分為新生代和老年代,根據(jù)年代的特點采用最適當?shù)氖占惴ā?/p>

GC收集器有哪些?CMS收集器與G1收集器的特點。

Serial: 單線程收集器,只會使用一個CPU或一條收集器線程去完成,垃圾回收工作,更重要的是在進行垃圾回收時,必須暫停其他所有的工作線程。(Stop the world)。簡單高效,用于新生代。ParNew: 是Serial收集器的多線程版本,垃圾回收時采用多線程方式進行回收。默認情況下使用的線程數(shù)是cpu數(shù)量。除了serial收集器,目前只有它能和CMS收集器配合工作。Parallel Scavenge: 使用復制算法收集器,也是一個并行的多線程收集器。Parallel Scavenge收集器與其他收集器關(guān)注點不同,其它收集器主要關(guān)注縮短垃圾回收時用戶線程的停頓時間。而它關(guān)心吞吐量,即運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)。停頓時間越短越適合需要與用戶交互的程序,高吞吐量則可以最高效率的利用CPU時間。Serial Old: 老年代,單線程收集器,使用標記整理算法。主要有兩個用途,一是和Parallel Scavenge 收集器配合使用,二是作為CMS的后備方案在并發(fā)收集器發(fā)生Concurrent Mode Failure時候使用。Parallel Old:并行的老年代版本收集器,使用標記整理算法。主要與Parallel Scavenge配合使用。CMS:是以獲得最短回收停頓時間為目標的收集器,使用標記清除算法。整個過程包括4個:初始標記: 標記Gc ROOTS能直接關(guān)聯(lián)到的對象并發(fā)標記:進行Roots Traceing的過程重新標記:修正并發(fā)標記期間因用戶繼續(xù)工作導致標記產(chǎn)生變動并發(fā)清除: 初始標記和重新標記需要stop the world. 并發(fā)標記和并發(fā)清除過程用戶線程和收集器線程可以并行執(zhí)行。G1(Garbage First):基于標記-整理算法的收集器,不會產(chǎn)生空間碎片.它可以精確控制停頓,能夠讓使用者明確指定一個長度為M毫秒的時間片段內(nèi),消耗集上的時間不超過N秒.是不犧牲吞吐量的前提下完成低停頓的.G1將整個java堆(新生和老生)劃分為大小相同的區(qū),并跟蹤這些區(qū)上發(fā)生的變化.在后臺維護一個優(yōu)先列表,每次根據(jù)允許的收集時間優(yōu)先回收垃圾最多的區(qū)域.

Minor GC與Full GC分別在什么時候發(fā)生?

FullGC 一般是發(fā)生在老年代的GC,出現(xiàn)一個FullGC經(jīng)常會伴隨至少一次的Minor GC。速度比MinorGC慢10倍以上。FULL GC發(fā)生的情況: 1) 老年代空間不足 老年代空間只有在新生代對象轉(zhuǎn)入及創(chuàng)建為大對象、大數(shù)組時才會出現(xiàn)不足的現(xiàn)象,當執(zhí)行Full GC后空間仍然不足,則拋出如下錯誤:java.lang.OutOfMemoryError: Java heap space . 措施:為避免以上兩種狀況引起的FullGC,調(diào)優(yōu)時應(yīng)盡量做到讓對象在Minor GC階段被回收、讓對象在新生代多存活一段時間及不要創(chuàng)建過大的對象及數(shù)組 2) Permanet Generation(方法區(qū)或永久代)空間滿 PermanetGeneration中存放的為一些class的信息等,當系統(tǒng)中要加載的類、反射的類和調(diào)用的方法較多時,Permanet Generation可能會被占滿,在未配置為采用CMS GC的情況下會執(zhí)行Full GC。如果經(jīng)過Full GC仍然回收不了,那么JVM會拋出如下錯誤信息: java.lang.OutOfMemoryError: PermGen space 措施:為避免Perm Gen占滿造成Full GC現(xiàn)象,可采用的方法為增大Perm Gen空間或轉(zhuǎn)為使用CMS GC。 3) CMS GC時出現(xiàn)promotion failed和concurrent mode failure 對于采用CMS進行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure兩種狀況,當這兩種狀況出現(xiàn)時可能會觸發(fā)Full GC。 promotion failed是在進行Minor GC時,survivor space放不下、對象只能放入老年代,而此時老年代也放不下造成的; concurrent mode failure: CMS在執(zhí)行垃圾回收時需要一部分的內(nèi)存空間并且此刻用戶程序也在運行需要預(yù)留一部分內(nèi)存給用戶程序,如果預(yù)留的內(nèi)存無法滿足程序需求就出現(xiàn)一次"Concurrent mod failure",并觸發(fā)一次Full GC。 應(yīng)對措施為:增大survivor space、老年代空間或調(diào)低觸發(fā)并發(fā)GC的比率, 4) 統(tǒng)計得到的Minor GC晉升到舊生代的平均大小大于舊生代的剩余空間 Hotspot為了避免由于新生代對象晉升到舊生代導致舊生代空間不足的現(xiàn)象,在進行Minor GC時,做了一個判斷,如果之前統(tǒng)計所得到的Minor GC晉升到舊生代的平均大小大于舊生代的剩余空間,那么就直接觸發(fā)Full GC。如果小于并且不允許擔保失敗也會發(fā)生一次Full GC

MinorGC MinorGC 指發(fā)生在新生代的垃圾收集動作,非常頻繁,回收速度也快。一般發(fā)生在新生代空間不足時,另外一個FullGC經(jīng)常會伴隨至少一次的Minor GC. 當虛擬檢測晉升到到老年代的平均大小是否小于老年代剩余空間大小,如果小于并且允許擔保失敗,則執(zhí)行Minor GC.http://zhidao.baidu.com/link?url=hxwfrDGb87nYAAaKh6kQerv45RzwFkGWOcvl9wbaKVwb8rjdiQNgxLy19ga_A0W8ozisKwCkrSlMjISwB1PeDcoXN9Z7qf12CdEm19VxiuO

幾種常用的內(nèi)存調(diào)試工具:jmap、jstack、jconsole。

(如何用工具分析jvm狀態(tài))jps: 列出正在虛擬機運行的虛擬機進程,并顯示虛擬機執(zhí)行主類的名稱,以及這些進程的本地虛擬機的唯一ID。jstat: 監(jiān)視虛擬機各種運行狀態(tài)信息的命令。可以顯示本地或遠程虛擬機進程中類裝載,垃圾收集,JIT編譯,內(nèi)存等數(shù)據(jù)。jinof: 實時查看和調(diào)整虛擬機的各項參數(shù)。jmap: 生成堆轉(zhuǎn)存儲快照,查詢fianlize執(zhí)行隊列、java堆和永生代詳細信息,如空間使用率,當前用的是那種收集器。Jhat: 和jmap搭配使用,來分析jmap生成的堆轉(zhuǎn)存儲快照。內(nèi)置一個微型的HTTP/HTML服務(wù)器,生成dump文件的分析結(jié)果后,可以通過瀏覽器查看。jstack:用于生成當前時刻線程快照.線程快照是當前虛擬機內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合.生成線程快照的主要目的是為了定位線程長時間停頓的原因.如死鎖,死循環(huán),請求外部資源導致的長時間等待.JConsole:可視化監(jiān)視和管理工具,幾乎包括以上工具的所有功能VisualVM

GC 是什么?為什么要有 GC

答:GC 是垃圾收集的意思,內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯誤的內(nèi)存回收會導致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java 提供的 GC 功能可以自動監(jiān)測對象是否超過作用域從而達到自動回收內(nèi)存的目的,Java 語言沒有提供釋放已分配內(nèi)存的顯示操作方法。Java 程序員不用擔心內(nèi)存管理,因為垃圾收集器會自動進行管理。要請求垃圾收集,可以調(diào)用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但 JVM 可以屏蔽掉顯示的垃圾回收調(diào)用。

垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個單獨的低優(yōu)先級的線程運行,不可預(yù)知的情況下對內(nèi)存堆中已經(jīng)死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調(diào)用垃圾回收器對某個對象或所有對象進行垃圾回收。在 Java 誕生初期,垃圾回收是 Java 最大的亮點之一,因為服務(wù)器端的編程需要有效的防止內(nèi)存泄露問題,然而時過境遷,如今 Java 的垃圾回收機制已經(jīng)成為被詬病的東西。移動智能終端用戶通常覺得 iOS 的系統(tǒng)比 Android 系統(tǒng)有更好的用戶體驗,其中一個深層次的原因就在于 Android 系統(tǒng)中垃圾回收的不可預(yù)知性。

JVM 加載 class 文件的原理機制

JVM 中類的裝載是由類加載器(ClassLoader) 和它的子類來實現(xiàn)的,Java 中的類加載器是一個重要的 Java 運行時系統(tǒng)組件,它負責在運行時查找和裝入類文件中的類。 由于 Java 的跨平臺性,經(jīng)過編譯的 Java 源程序并不是一個可執(zhí)行程序,而是一個或多個類文件。當 Java 程序需要使用某個類時,JVM 會確保這個類已經(jīng)被加載、連接(驗證、準備和解析)和初始化。類的加載是指把類的 .class 文件中的數(shù)據(jù)讀入到內(nèi)存中,通常是創(chuàng)建一個字節(jié)數(shù)組讀入 .class 文件,然后產(chǎn)生與所加載類對應(yīng)的 Class 對象。加載完成后,Class 對象還不完整,所以此時的類還不可用。當類被加載后就進入連接階段,這一階段包括驗證、準備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認的初始值)和解析(將符號引用替換為直接引用)三個步驟。最后 JVM 對類進行初始化,包括:1. 如果類存在直接的父類并且這個類還沒有被初始化,那么就先初始化父類;2. 如果類中存在初始化語句,就依次執(zhí)行這些初始化語句。 類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從JDK 1.2開始,類加載過程采取了父親委托機制(PDM)。PDM 更好的保證了 Java 平臺的安全性,在該機制中,JVM 自帶的 Bootstrap 是根加載器,其他的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載,父類加載器無能為力時才由其子類加載器自行加載。JVM 不會向 Java 程序提供對 Bootstrap 的引用。下面是關(guān)于幾個類加載器的說明: a)Bootstrap:一般用本地代碼實現(xiàn),負責加載JVM基礎(chǔ)核心類庫(rt.jar); b)Extension:從 java.ext.dirs 系統(tǒng)屬性所指定的目錄中加載類庫,它的父加載器是 Bootstrap; c)System:又叫應(yīng)用類加載器,其父類是Extension。它是應(yīng)用最廣泛的類加載器。它從環(huán)境變量 classpath 或者系統(tǒng)屬性 java.class.path 所指定的目錄中記載類,是用戶自定義加載器的默認父加載器。

類加載的五個過程:加載、驗證、準備、解析、初始化。

加載: 根據(jù)全限定名來獲取定義類的二進制字節(jié)流,然后將該字節(jié)流所代表的靜態(tài)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu),最后在java堆上生成一個代表該類的Class對象,作為方法區(qū)這些數(shù)據(jù)的訪問入口.驗證:主要時為了確保class文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全.包含四個階段的驗證過程: 1)文件格式驗證:保證輸入的字節(jié)流能夠正確地解析并存儲在方法區(qū)之內(nèi),格式上符合描述一個java類型信息的要求 2)元數(shù)據(jù)驗證:字節(jié)碼語義信息的驗證,以保證描述的信息符合java語言規(guī)范.驗證點有:這個類是否有父類等. 3)字節(jié)碼驗證:主要是進行數(shù)據(jù)流和控制流分析,保證被校驗類的方法在運行時不會做出危害虛擬機安全的行為. 4)符號引用驗證:對符號引用轉(zhuǎn)化為直接引用過程的驗證.準備:為類變量分配內(nèi)存并設(shè)置變量的初始值,這些內(nèi)存在方法區(qū)進行分配.解析:將虛擬機常量池中的符號引用轉(zhuǎn)化為直接引用的過程.解析主要是針對類或接口,字段,類方法,類幾口方法四類.初始化:執(zhí)行靜態(tài)變量的賦值操作以及靜態(tài)代碼塊,完成初識化.初始化過程保證了父類中定義的初始化優(yōu)先于子類的初始化.但接口不需要執(zhí)行父類的初始化.

雙親委派模型:

除了頂層的啟動類加載器外,其余的類加載器都應(yīng)當有自己的父類加載器.順序依次是: Bootstrap ClassLoader: 啟動類加載器,加載java_home/lib中的類 Extension ClassLoader: 擴展類加載器,加載java_home/lib/ext目錄下的類庫 Application ClassLoader: 應(yīng)用程序類加載器,加載用戶類路徑上指定類庫. 雙親委派模型的工作原理是:如果一個類加載器受到了類加載請求,它首先不會自己去嘗試加載這個類,而把這個請求委派給父類加載器去完成,每一層次的類加載器都是如此,因此所有的加載請求最終都應(yīng)該傳送到頂層的啟動類加載器中,只有當父類加載器反饋自己無法完成加載請求時,加載器才嘗試自己加載.這種方式保證了Oject類在各個加載器加載環(huán)境中都是同一個類.

分派:靜態(tài)分派與動態(tài)分派。

多態(tài)性特征的一些最基本的體現(xiàn). 靜態(tài)類型是編譯器可知的,動態(tài)類型是在運行時可知.Human h =new Man(); Human是靜態(tài)類型,Man時動態(tài)類型. 所有依賴于靜態(tài)類型定義方法執(zhí)行版本的分配動作稱作靜態(tài)分派,最典型的應(yīng)用是方法重載.動態(tài)分派是根據(jù)動態(tài)類型來確定執(zhí)行的版本,所以只有到運行時才能確定具體的執(zhí)行方法版本.典型的代表時重寫.其過程如下: 1)首先找到操作數(shù)棧棧頂?shù)牡谝粋€元素所執(zhí)向?qū)ο蟮膶嶋H類型,記做C. 2) 如果在類型C中找到和常量中的描述符和簡單名稱都相符的方法,則進行范圍權(quán)限校驗.如果通過則返回該方法的直接引用,否則拋出IllegalAccessError異常. 3) 否則按照繼承關(guān)系從下往上一次對C的各個父類進行第2步的搜索和驗證過程. 4) 如果始終沒有找到舊拋出AbstractMethodError異常. 方法的接受者和方法的參數(shù)統(tǒng)稱方法宗量,根據(jù)分配基于多少中宗量可以分為單分派和多分派.java是靜態(tài)多分派,動態(tài)分派屬于單分派.

動態(tài)分派的實現(xiàn):動態(tài)分派時非常頻繁的動作,而且動態(tài)分派的方法版本選擇過程需要運行時在類的方法元數(shù)據(jù)中搜索合適的目標方法,因此出于性能的考慮,在方法區(qū)中建立一個虛方法表,用來保存各個方法的實際入口地址.如果某個方法的子類中沒有被重新,那么子類的虛方法表里面的地址入口和父類相同方法的地址入口是一致的.都是指向父類的實現(xiàn)入口,如果子類中重寫了這個方法,子類方法表中的地址將會被替換為指向子類實現(xiàn)版本的入口地址.虛方法表在類加載的連接階段進行初始化.

Jvm 自動內(nèi)存管理(什么時候觸發(fā) gc )

http://jeromecen1021.blog.163.com/blog/static/18851527120117274624888/FULL GC 和 Minor GC 的觸發(fā)時間 程序員不能具體控制時間,系統(tǒng)在不可預(yù)測的時間調(diào)用System.gc()函數(shù)的時候;當然可以通過調(diào)優(yōu),用NewRatio控制newObject和oldObject的比例,用MaxTenuringThreshold 控制進入oldObject的次數(shù),使得oldObject 存儲空間延遲達到full gc,從而使得計時器引發(fā)gc時間延遲OOM的時間延遲,以延長對象生存期。

GC停頓原因,如何降低停頓

JVM如何調(diào)優(yōu)、參數(shù)怎么調(diào)

jvm的體系結(jié)構(gòu)及各個部分的職責

JVM都有兩種機制,一個是裝載具有合適名稱的類(類或是接口),包含類的裝載 連接 初始化的過程叫做類裝載子系統(tǒng);另外的一個負責執(zhí)行包含在已裝載的類或接口中的指令,叫做運行引擎。每個JVM又包括方法區(qū)、堆、Java棧、程序計數(shù)器和本地方法棧這五個部分,這幾個部分和類裝載機制與運行引擎機制一起組成的體系結(jié)構(gòu)圖為:

JVM的每個實例都有一個它自己的方法域和一個堆,運行于JVM內(nèi)的所有的線程都共享這些區(qū)域;當虛擬機裝載類文件的時候,它解析其中的二進制數(shù)據(jù)所包含的類信息,并把它們放到方法域中;當程序運行的時候,JVM把程序初始化的所有對象置于堆上;而每個線程創(chuàng)建的時候,都會擁有自己的程序計數(shù)器和Java棧,其中程序計數(shù)器中的值指向下一條即將被執(zhí)行的指令,線程的Java棧則存儲為該線程調(diào)用Java方法的狀態(tài);本地方法調(diào)用的狀態(tài)被存儲在本地方法棧,該方法棧依賴于具體的實現(xiàn)。

http://blog.csdn.net/dongdong_java/article/details/24797307http://blog.csdn.net/longyulu/article/details/8350622

如果想不被 GC 怎么辦

可以先說那些對象可以被GC,然后說java對象會不會回收,決定于是否還被引用,不被引用了就有可能被GC回收,一直被引用著就不會被回收.

jvm性能調(diào)優(yōu)都做了什么

介紹GC 和GC Root不正常引用。

自己從classload 加載方式,加載機制說開去,從程序運行時數(shù)據(jù)區(qū),講到內(nèi)存分配,講到String常量池,講到JVM垃圾回收機制,算法,hotspot。反正就是各種擴展

數(shù)組多大放在 JVM 老年代(不只是設(shè)置 PretenureSizeThreshold ,問通常多大,沒做過一問便知)

老年代中數(shù)組的訪問方式

GC 算法,永久代對象如何 GC , GC 有環(huán)怎么處理

jvm 如何分配直接內(nèi)存??

new 對象如何不分配在堆而是棧上?

常量池解析

運行期優(yōu)化

最佳實踐

Student s= new Student(),在內(nèi)存中做了那些事情

加載Student.class 文件進內(nèi)存

在棧內(nèi)存為s開辟空間

在堆內(nèi)存為學術(shù)對象開辟空間

學生對象的成員變量進行顯示初始化

通過構(gòu)造方法對學生對象變量賦值

學生對象初始完畢,把對象地址賦值給s變量

常用參數(shù)配置

參數(shù) 含義 默認值 備注 -Xms:表示初始堆大小,默認為物理內(nèi)存的1/64(<1GB) 默認(MinHeapFreeRatio參數(shù)可以調(diào)整)空余堆內(nèi)存小于40%時,JVM就會增大堆直到-Xmx的最大限制. -Xmx 最大堆大小 物理內(nèi)存的1/4(<1GB) 默認(MaxHeapFreeRatio參數(shù)可以調(diào)整)空余堆內(nèi)存大于70%時,JVM會減少堆直到 -Xms的最小限制 -Xmn 年輕代大小(1.4or lator) 注意:此處的大小是(eden+ 2 survivor space).與jmap -heap中顯示的New gen是不同的。 整個堆大小=年輕代大小 + 年老代大小 + 持久代大小. 增大年輕代后,將會減小年老代大小.此值對系統(tǒng)性能影響較大,Sun官方推薦配置為整個堆的3/8 -XX:NewSize 設(shè)置年輕代大小(for 1.3/1.4)

-XX:MaxNewSize 年輕代最大值(for 1.3/1.4)

-XX:PermSize 設(shè)置持久代(perm gen)初始值 物理內(nèi)存的1/64

-XX:MaxPermSize 設(shè)置持久代最大值 物理內(nèi)存的1/4

-Xss 每個線程的堆棧大小 JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K.更具應(yīng)用的線程所需內(nèi)存大小進行 調(diào)整.在相同物理內(nèi)存下,減小這個值能生成更多的線程.但是操作系統(tǒng)對一個進程內(nèi)的線程數(shù)還是有限制的,不能無限生成,經(jīng)驗值在3000~5000左右 一般小的應(yīng)用, 如果棧不是很深, 應(yīng)該是128k夠用的 大的應(yīng)用建議使用256k。這個選項對性能影響比較大,需要嚴格的測試。(校長) 和threadstacksize選項解釋很類似,官方文檔似乎沒有解釋,在論壇中有這樣一句話: -Xss is translated in a VM flag named ThreadStackSize 一般設(shè)置這個值就可以了。 -XX:NewRatio 年輕代(包括Eden和兩個Survivor區(qū))與年老代的比值(除去持久代)

-XX:NewRatio = 4表示年輕代與年老代所占比值為1:4, 年輕代占整個堆棧的1/5 Xms = Xmx并且設(shè)置了Xmn的情況下,該參數(shù)不需要進行設(shè)置。 -XX:SurvivorRatio Eden區(qū)與Survivor區(qū)的大小比值 設(shè)置為8,則兩個Survivor區(qū)與一個Eden區(qū)的比值為2:8,一個Survivor區(qū)占整個年輕代的1/10 -XX:MaxTenuringThreshold 垃圾最大年齡 如果設(shè)置為0的話,則年輕代對象不經(jīng)過Survivor區(qū),直接進入年老代. 對于年老代比較多的應(yīng)用,可以提高效率.如果將此值設(shè)置為一個較大值,則年輕代對象會在Survivor區(qū)進行多次復制,這樣可以增加對象再年輕代的存活 時間,增加在年輕代即被回收的概率 該參數(shù)只有在串行GC時才有效.

-XX:PretenureSizeThreshold 對象超過多大是直接在舊生代分配 0 單位字節(jié) 新生代采用Parallel Scavenge GC時無效 另一種直接在舊生代分配的情況是大的數(shù)組對象,且數(shù)組中無外部引用對象.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從三月份找實習到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,873評論 11 349
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準確的地方,同時不同JDK版本的...
    高廣超閱讀 16,063評論 3 83
  • 所有知識點已整理成app app下載地址 J2EE 部分: 1.Switch能否用string做參數(shù)? 在 Jav...
    侯蛋蛋_閱讀 2,713評論 1 4
  • 原文閱讀 前言 這段時間懈怠了,罪過! 最近看到有同事也開始用上了微信公眾號寫博客了,挺好的~給他們點贊,這博客我...
    碼農(nóng)戲碼閱讀 6,163評論 2 31
  • 如果你的演講需要拍成視頻,放到網(wǎng)上傳播或者供他人觀看,PPT背景最好選擇深色。因為深色背景不會反光,不會顯得演講人...
    金貓貓閱讀 243評論 0 0

友情鏈接更多精彩內(nèi)容