[總結]-第二章 Java內存區域與內存溢出異常

[總結]-第二章 Java內存區域與內存溢出異常

1、知識點

一、虛擬機運行時數據區

  • 方法區:運行時常量池(JDK1.7被移出)
  • 堆:存放對象實例或數組新生代和老年代
  • 虛擬機棧:線程私有
  • 本地方法棧:線程私有Native
  • 程序計數器:線程私有行號指示器無OOM

字節碼解釋器工做時就是經過改變程序計數器的值來選取下一條須要執行的字節碼指令。java

二、Java堆的內存分配方式

  • 指針碰撞(內存規整)
  • 空閒列表(內存不規整)

選擇哪一種分配方式由Java堆是否規整決定,而Java堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。數組

三、對象的內存佈局

  • 對象頭
    • 對象自身運行時數據(Mark Word) - 若是32bit
      • 哈希碼(25bit)[未鎖定時]
      • GC分代年齡(4bit)[未鎖定時]
      • 鎖狀態標誌位(2bit)
        • 01 未鎖定 [未鎖定時]
        • 01 偏向鎖 [鎖定時]
        • 00 輕量級鎖 [鎖定時]
        • 10 重量級鎖 [鎖定時]
        • 11 GC標記
      • 固定爲0(1bit)
    • 類型指針:對象指向它的類元數據的指針,虛擬機經過這個指針判斷此對象是哪一個類的實例。
  • 實例數據:程序代碼中定義的各類類型的字段內容。
  • 對齊填充:僅僅是佔位符。

四、對象的訪問定位

  • 使用句柄 -> 句柄池安全

    • reference中存儲的就是對象的句柄地址
    • 好處:reference中存儲的是穩定的句柄地址,在對象被移動(GC時移動)時只會改變句柄中的實例數據指針,而reference自己不須要修改。
  • 直接指針微信

    • reference中存儲的直接就是對象地址
    • 好處:速度更快,節省一次指針定位的時間開銷。

2、名詞解釋

  1. JIT編譯器:Just in time compiler 即時編譯器;
  2. 字面量:文本字符串,聲明爲final的常量池;
  3. 符號引用:類和接口的全限定名(包名+類名)、字段的名稱和描述符、方法的名稱和描述符;
  4. 偏向鎖:是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖,下降獲取鎖的代價;
  5. CAS:Compare And Swap 比較交換;
  6. 逃逸分析:開啓逃逸分析,直接棧上分配;

3、常見問題:

一、程序計數器爲何不會內存溢出?

由於程序計數器中存儲的數據所佔空間的大小不會隨着程序的執行而發生改變。多線程

二、intern()的使用?

JDK1.6在常量池建立與此String內容相同的字符串;常量池 建立字符串->返回引用 JDK1.7在常量池中記錄Heap中首次出現的引用,並返回該引用。常量池 記錄引用->返回引用app

String str1 = new StringBuilder("計算機").append("軟件").toString();
System.out.println((str1.intern() == str1));
//JDK1.6:false
//JDK1.7:true

三、String s = new String("你好");建立了幾個對象?

  • 直接使用雙引號聲明出來的String對象會直接存儲在常量池
  • 使用new,JVM會在中建立一個內容相同的String對象,而後返回堆中String對象的引用。

四、內存分配怎麼解決線程安全問題?

  • 對分配內存空間的動做進行同步處理-採用CAS配上失敗重試的方式保證更新操做的原子性;
  • 把內存分配的動做按照線程劃分在不一樣的空間之中進行,即每一個線程在Java堆中預先分配一小塊內存,稱爲本地線程分配緩衝(TLAB)

五、CAS是什麼?

CAS(Compare And Swap 比較交換),是無鎖執行者,能夠用來保證線程執行的安全性。核心思想以下:函數

執行函數:CAS(V,E,N)

其包含3個參數佈局

  • V 表示要更新的變量
  • E 表示預期值
  • N 表示新值

若是V值等於E值,則將V的值設爲N。若V值和E值不一樣,則說明已經有其餘線程作了更新,此時當前線程不執行更新操做,但能夠選擇從新讀取該變量再嘗試再次修改該變量,也能夠放棄操做。ui

CAS是一條CPU的原子指令,完成某個功能的一個過程的原語的執行必須是連續的,不會形成所謂的數據不一致問題。spa

六、字節與byte與bit的關係

1 字節 = 1 byte = 8 bit

七、如何避免堆自動擴展?

將堆的最小值-Xms參數與最大值-Xmx參數設置爲同樣便可避免堆自動擴展。

八、常見OOM有哪些?分別怎麼分析定位?

java.lang.OutOfMemoryError: Java heap space

堆內存溢出(最多見的),能夠Dump堆轉儲快照信息查看具體問題。

java.lang.StackOverflowError

虛擬機棧內存溢出 - 超出當前方法棧深度

java.lang.OutOfMemoryError: unable to create new native thread

多線程致使內存溢出,可經過「減小最大堆」和「減小棧容量」來換取更多的線程。

java.lang.OutOfMemoryError: PermGen space

出現這個異常說明運行時常量池屬於方法區的一部分,能夠手動設置MaxPermSize大小修改。 jdk1.7已經將常量池從方法區移出,jdk1.8徹底刪除永久代,全部jdk1.8不會出現此OOM。

java.lang.OutOfMemoryError

由DirectMemory(本機直接內存)致使的OOM,沒有明顯的異常說明,由於這裏的內存不足時它自己計算出來,並手動拋出異常。

4、常見命令

-XX:+HeapDumpOnOutOfMemoryError

可讓虛擬機在出現OOM時Dump出當前的內存堆轉儲快照以便過後進行分析

-Server -XX:+DoEscapeAnalysis

開啓逃逸分析,直接棧上分配

-XX:MaxDirectMemorySize

指定本機直接內存容量,默認爲java堆最大值-Xmx

博客

https://my.oschina.net/gmarshal

歡迎關注個人我的微信訂閱號:(聽說這個頭像程序猿專用)

輸入圖片說明

相關文章
相關標籤/搜索