java虛擬機(JVM)常用知識點整理

知識點整理:

  1. java運行時數據區域(內存模型)
      1. Enden、from survivor、to survivor
      2. 老年代:大對象、15輪、相同多
      3. 存放實例、實例變量、數組
    1. 方法區
      1. 類信息、常量池、靜態變量
    2. 棧 私有
      1. 棧幀:
        1. 局部變量表:局部變量---基本數據、對象引用、返回地址類型
        2. 操作數棧:算數運行、遞歸時的參數傳遞
        3. 動態鏈接:指向常量池中的符號引用,運行期間轉化爲直接引用
        4. 方法返回地址:
          1. return正常出口---恢復上一個棧幀數據、返回值入操作數棧、調用程序計數器
          2. 異常出口:異常處理器
    3. 程序計數器:字節碼指令的行號指示器、私有
    4. OOM:
      1. Java heap spacess:內存泄露【垃圾對象太多】、內存溢出
      2. PermGen space:類信息過多、常量過多
      3. stackOverflowerError:遞歸深度、死循環
  2. GC 可達性分析:棧、方法區靜態、常量池引用對象
    1. gc機制:分代收集:新生代--複製、老年代--標記整理
    2. 垃圾收集器:Parallel Scavenge(old)吞吐量、CMS服務響應速度、G1
    3. gc觸發:minor、full觸發(空間分配擔保)
    4. gc過程:引用鏈OopMap、安全點、安全區
  3. 對象內存 對象頭、實例數據、對齊
    1. 訪問定位:句柄、直接指針
    2. new對象過程
    3. 類加載過程
      1. 類加載器:雙親委派模型
      2. 觸發時機:new、靜態、反射、先加載父類

jvm的內存佈局 

JVM內存結構主要有三大塊:堆內存、方法區、棧

  • 堆內存是JVM中最大的一塊,由年輕代和老年代組成,線程共享
    • 年輕代內存又被分成三部分,Eden空間、From Survivor空間、To Survivor空間,默認情況下年輕代按照8:1:1的比例來分配;
  • 方法區存儲類信息、常量池、靜態變量等數據,線程共享
  • 棧分爲java虛擬機棧、本地方法棧,主要用於方法的執行,線程私有

 

爲什麼兩個倖存空間 From Survivor、To Survivor 解決碎片問題

引進了“倖存區”作用:

  1. 降低gc頻率,如果活着的對象全部進入老年代,老年代很快被填滿,Full GC 的頻率大大增加
  2. 解決碎片問題
  3. Eden 空間快滿時 Minor GC ,頻率得以降低

缺點:兩個 Survivor ,10%的空間浪費、複製對象開銷

機制

  1. 如果對象在新生代 gc 之後任然存活,暫時進入倖存區;以後每過一次 gc ,對象年齡+1,直到某個設定的值15或直到“To”區被填滿,“To”區被填滿之後,會將所有對象移動到年老代中
  2. 把 Eden : From Survivor : To Survivor 空間大小設成 8 : 1 : 1 ,對象總是在 Eden 區出生, From Survivor 保存當前的倖存對象, To Survivor 爲空。一次 gc 發生後: 
    1. Eden 區活着的對象 + From Survivor 存儲的對象被複制到 To Survivor ; 
    2. 清空 Eden 和 From Survivor ; 
    3. 顛倒 From Survivor 和 To Survivor 的邏輯關係: From 變 To , To 變 From

 

介紹jvm每個區域的作用 堆、方法區、棧、程序計數器

Java堆(Heap)

  1. 虛擬機啓動時創建,內存中最大的一塊,線程共享
  2. 存放對象實例、數組、實例成員變量
  3. 垃圾收集器管理的主要區域,也被稱做“GC堆”,邏輯上連續,一般採用分代收集算法

方法區(Method Area)

  1. 線程共享,存儲已被虛擬機加載的,類加載器 加載的---
    1. 類信息:
    2. 常量池:靜態常量池:編譯期生成的字面量【final常量】和符號引用 ;運行時常量池:jvm虛擬機在完成類裝載操作後,運行期間生成的新常量
    3. 靜態變量、編譯器編譯後的靜態變量數據
    4. 即時編譯器編譯後的代碼
  2. 內存回收目標主要是常量池的回收和對類型的卸載 

 

常量池的好處

常量池是爲了避免頻繁的創建和銷燬對象而影響系統性能,其實現了對象的共享

例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中

  1. 節省內存空間:常量池中所有相同的字符串常量被合併,只佔用一個空間
  2. 節省運行時間:比較字符串時,==比equals()快。對於兩個引用變量,只用==判斷引用是否相等,也就可以判斷實際值是否相等

 

JVM棧(JVM Stacks)

Java虛擬機棧

  1. 線程私有,生命週期與線程相同
  2. 描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作數棧、動態連接(指向常量池)、方法返回地址等信息。每一個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程 
    1. 局部變量表:局部變量:方法參數和方法內部定義的變量,局部變量表所需的內存空間在編譯期間完成分配;【隨着方法的消失而消失】
      1. 編譯期可知的基本數據類型(boolean、byte、char、short、int、float、long、double)
      2. 對象or數組引用(作爲參數)(reference類型 指針指向,內存數據存在堆中,類型信息存儲在方法區)
      3. 返回地址類型(指向了一條字節碼指令的地址)
    2. 操作數棧:先入後出,初始爲空,在方法的執行過程中加入數據: 算術運算、方法參數、方法返回值
    3. 動態連接:棧幀包含的一個指針:指向運行時常量池中,所屬方法的符號引用,在運行期間將符號引用轉化爲直接引用稱爲動態鏈接
    4. 方法返回地址 兩種方式退出:
      1. 正常完成出口:是執行引擎遇到一個return的字節碼指令,恢復上層方法的局部變量表和操作數棧,把返回值壓入調用者棧幀的操作數棧中,然後調用程序計數器執行後一條指令。
      2. 異常完成出口:方法執行過程中遇到了異常,異常沒有在方法體內得到處理,返回地址由異常處理器確定

本地方法棧(Native Method Stacks)

本地方法棧則是爲虛擬機使用到的Native本地方法服務

 

程序計數器(Program Counter Register)

  1. 線程私有,一塊較小的內存空間
  2. 當前線程所執行的字節碼指令的行號指示器
    1. 通過改變這個計數器的值來選取下一條字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成
  3. 每條線程都需要有一個獨立的程序計數器,各條線程之間的計數器互不影響

可達性分析+分代收集+回收算法

可達性分析=引用鏈枚舉 判斷一個對象是否存活、GC對象的判定方法

判斷一個對象是否存活有兩種方法:

1.引用計數法 xxx

對象設置引用計數器,引用對象時,計數器加一;引用失效時,計數器就減一;爲零時,垃圾回收

缺陷:無法解決循環引用問題,也就是說當對象A引用對象B,對象B又引用者對象A,引用計數器都不爲零,無法垃圾回收

2.可達性算法(引用鏈法) 棧、方法區的引用對象

從一個被稱爲GC Roots的對象開始向下搜索,如果一個對象到GC Roots沒有引用鏈相連時,則說明此對象不可用

  • 虛擬機棧中引用的對象
  • 本地方法棧JNI引用的對象
  • 方法區靜態變量引用的對象
  • 方法區常量池引用的對象

當一個對象不可達GC Root時,這個對象並不會立馬被回收,被真正的回收需要經歷兩次標記

可達性分析中沒有與GC Root的引用鏈,此時第一次標記並且進行一次篩選,篩選的條件是是否有必要執行finalize()方法

若有必要執行finalize()方法,對象將會放在F-Queue隊列中,虛擬機會觸發一個Finalize()線程去執行,GC對處於F-Queue中的對象進行第二次被標記,這時,該對象將被移除”即將回收”集合,等待回收

 

HotSpot 基於安全點的引用鏈枚舉 (GC)

  1. 準確式GC 快速完成GC Roots引用鏈枚舉
    1. 引用鏈枚舉時,應用OopMap數據結構,快速完成GC Roots引用鏈枚舉
    2. OopMap:在類加載完成時,存儲 :寄存器和棧的 <偏移量,數據及數據類型>;<k,v>
  2. 安全點檢測:程序有長時間執行特徵 --- 方法調用、循環跳轉、異常跳轉時
    1. 僅需在安全點記錄OopMap信息;每條指令生成OopMap,則空間成本太大;
    2. 程序執行時僅在安全點停下來GC
  3. 多線程的主動式中斷,使得各個線程都跑到安全點再停頓
    1. 在安全點、創建的對象分配內存時 設置一個標誌
    2. 各個線程執行時主動輪詢該標誌,若爲真,則中斷掛起
  4. 安全區域檢測:代碼中,引用關係不發生變化
    1. 線程沒有分配CPU時間,無法跑到安全點,導致代碼中,引用關係不發生變化
    2. GC時可忽略該標識自己處於安全區域的線程
    3. 要離開安全區域,需要收到系統已完成引用鏈枚舉的信號

 

java垃圾回收機制

  1. 自動:不需要顯示釋放對象內存,虛擬機自行執行
  2. GC時間:在虛擬機空閒、堆內存不足時觸發,低優先級垃圾回收線程
  3. GC對象:沒任何引用的對象(可達性算法)
  4. 方式:minorGC fullgc

java中垃圾回收的方法有哪些

  1. 標記-清除:x
    1. 標記哪些要被回收的對象,然後統一回收
    2. 特點:
      1. 標記和清除的效率低;
      2. 產生大量不連續的內存碎片,GC頻繁---以後程序在分配較大的對象時,由於沒有充足的連續內存導致GC頻繁
  1. 複製算法: 適合年輕代
    • 把 Eden : From Survivor : To Survivor 空間大小設成 8 : 1 : 1 ,對象總是在 Eden 區出生,若Eden區滿,觸發minor GC
    • 若GC後,存活的對象太多,to survivor內存不夠時,通過分配擔保機制複製到老年代;老年代 full gc
  1. 標記-整理 適合老年代
    1. 在清除對象的時候先將可回收對象移動到一端,然後清除掉端邊界以外的對象
      1. 解決大量內存碎片問題
      2. 當對象存活率較高時,效率也不差
  1. 分代收集  綜合
    1. 根據對象的生存週期,將堆分爲新生代和老年代
      1. 在新生代中,對象生存期短,採用複製算法
      2. 老年代裏的對象存活率較高,使用標記-整理 或者 標記-清除

5.G1收集器的可預測停頓

 

Jvm對象分配方案 分代機制 何時進入老年代

對象優先在Eden分配;Eden區沒有足夠空間時,發起一次MinorGC;

  1.  大對象直接進入老年代;

     通過 -XX:PretenureSizeThreshold參數設置;

  1.  長期存活的對象進入老年代:存活輪次多 15

    MinorGC一次還存活在Survivor中,年齡+1; 通過 -XX:MaxTenuringThreshold參數設置;

  1.  年齡相同的大於一半,動態對象年齡判別:

    在survivor中年齡相同的所有對象大小總和大於 survivor 一半,年齡大於或等於該年齡的對象進入老年代;防止survivor滿

  1.  空間(檢測)分配擔保機制:fullgc前 需要比較兩次

每次MinorGC之前,會檢查老年代最大連續可用空間是否大於 新生代所有對象的總空間,大於則表示安全,MinorGC;

    如果小於:(JDK 6U24不再檢查HandlePromotionFailure,一定會冒險)

    檢查HandlePromotionFailure 爲 true ,允許冒險,歷次晉升到老年代的對象平均大小與本次進入的對象大小比較,若歷次大 MinorGC,若小 FullGC;

    HandlePromotionFailure 爲 false,直接進行FullGC;

 

簡述minor和fullgc,minorGC以及FullGC觸發條件

  1. 新生代進行一次垃圾清理,被稱爲minorGC
  2. 老年代進行一次垃圾清理,被稱爲fullGC或者majorGC。速度一般較慢
  3. 大多數新生對象生命週期很短,所以MinorGC通常很頻繁,回收速度也較快
  4. 降低MinorGC的頻率、減少fullGC的次數

觸發條件:

MinorGC:Eden區滿時觸發MinorGC;FullGC也會伴隨有MinorGC;

FullGC:a. 老年代不夠分配時,觸發FullGC;

b. 空間(檢測)分配擔保機制:MinorGC觸發前,比較老年代的剩餘空間和新生代所有對象大小,老年代小,且不允許冒險,則fullgc

允許冒險,繼續比較對象歷次平均大小與本次進入老年代的大小,若本次大,則FullGC;

爲什麼要擔保:每次minorgc,新生代年齡滿15的會進入老年代,如果新生代全部對象都一起滿15會導致老年代不夠放

    c. 手動調用System.gc(),提醒JVM FullGC,但不可控;

 

棧溢出、堆溢出、內存溢出的原因

棧溢出的原因

  • 遞歸調用
  • 大量循環、死循環
  • 函數體內局部變量數組過大

內存溢出的原因是什麼

  1. JVM沒有及時回收,堆內存泄露
  2. 循環或遞歸中大量的new對象,堆溢出
  3. 靜態變量大、類加載過多,類信息、方法區溢出
  4. 函數體內的數組過大,棧溢出
  5. 遞歸或無限遞歸,棧溢出

oom類型

導致的原因

內存溢出 out of memory,是指程序在申請內存時,沒有足夠的內存空間供其使用

內存泄漏 memory leak,是指程序在申請內存後,無法釋放已申請的內存空間,最終會導致out of memory

1,Java Heap 溢出 

堆 存放對象實例和數組,線程共享;

  1. 內存不夠:實例過多、數組過大、大量的new對象;集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;
  2. 內存泄露:靜態集合類引起內存泄露;各種連接沒有關閉;單例對象持有外部對象的引用

 

一般的異常信息:java.lang.OutOfMemoryError:Java heap spacess  

 

先分清是內存泄漏還是內存溢出

內存泄漏

通過工具查看泄漏對象到GC Roots的引用鏈,找到泄漏對象與GC Roots相關聯路徑, 

內存溢出

檢查虛擬機的參數(-Xmx與-Xms)的設置是否適當 ;

通過內存映像分析工具(如Eclipse Memory Analyzer)對dump出來的堆轉存快照進行分析,確認內存中的對象是否是必要的

2, 方法區溢出 運行時常量池溢出 

常量池溢出;

加載到方法區的類過多;類信息過多:同一個類文件被不同的類加載器重複加載

用於存儲已被JVM加載的類信息、常量池、靜態變量等。編譯器編譯後的代碼,線程共享

異常信息:java.lang.OutOfMemoryError:PermGen space 

-XX:PermSize和-XX:MaxPermSize 設置方法區的大小

3, 虛擬機棧和本地方法棧溢出 

遞歸太深、死循環導致棧幀創建過多

線程請求的棧深度大於虛擬機允許的最大深度,拋出StackOverflowError異常 

在擴展棧時無法申請到足夠的內存,則拋出OutOfMemoryError異常 

棧的大小越大,可分配的線程數就越少

 

4, 本機直接內存溢出

java.lang.OutOfMemoryError

-XX:MaxDirectMemorySize指定,默認和Java堆最大值一樣

 

垃圾收集器 3類

1.吞吐量優先

Parallel Scavenge[ˈskævɪndʒ] 新生代 複製算法

parallel Old 老年代 標記-整理

2.重視服務響應速度,最短回收停頓時間

Parallel Scavenge[ˈskævɪndʒ] 新生代 複製算法

CMS(Concurrent Mark Sweep) 老年代 併發的標記-清除

  1. 初始標記(CMS initial mark)S
  2. 併發標記(CMS concurrent mark)
  3. 重新標記(CMS remark) S
  4. 併發清除(CMS concurrent sweep)

 

初始標記、重新標記:這兩個步驟仍然需要“Stop The World”【所有線程停止工作】

  1. 初始標記僅僅只是標記一下GC Roots能直接關聯到的對象【棧、方法區】,速度很快,要“Stop The World”
  2. 併發標記階段就是進行GC Roots Tracing【引用鏈跟蹤過程】的過程,剛纔產生的集合中標記出存活對象
  3. 重新標記階段則是爲了修正併發標記期間,因用戶程序繼續運作,而導致標記產生變動的 部分對象的標記記錄,要”Stop The World“
    1. 比初始標記階段稍長一些,但遠比並發標記的時間短
  4. 併發清理回收所有的垃圾對象,由於整個過程中耗時最長的併發標記和併發清除過程中,收集器線程都可以與用戶線程一起工作

缺點:

  1. CPU資源敏感(需要併發)
  2. 無法處理浮動垃圾(邊併發GC邊產生垃圾)
    1. 在默認設置下,CMS收集器在老年代使用了68%的空間後就會被激活
    2. 要是CMS運行期間預留的內存無法滿足程序需要,就會出現一次“Concurrent Mode Failure”失敗【運行時模式錯誤】
  3. 大量空間碎片(需要碎片整理)
    1. CMS收集器提供了一個-XX:+UseCMSCompactAtFullCollection開關參數,用於在“享受”完Full GC服務之後額外免費附送一個碎片整理過程

3.面向服務器端應用,低停頓

G1收集器

  1. 併發,邊GC邊執行代碼
  2. 分代收集:單個收集器,即可管理不同存活時間的對象
  3. 併發標記-整理算法,無空間碎片
  4. 可預測的停頓:可設定在長度爲M毫秒內,垃圾收集時間不超過N毫秒
    1. 實現方式:將堆劃分爲相等的region,設置一個價值標記,進行跟蹤;優先回收價值最大的region
    2. 價值標記:回收所獲得的空間大小和所需時間的經驗值,用優先隊列維護

 

初始標記 GC Roots能直接關聯到的對象 Stop the world

併發標記 從GC root開始對堆中的對象進行可達性分析、找出存活對象

最終標記 修正在併發標記其間,用戶程序繼續運行產生變動的標記記錄 S

篩選回收 對各個region回收價值和成本進行排序,根據用戶期望停頓時間進行回收 【S,或者併發回收】

 

類加載器

通過類的全限定名獲取該類的二進制字節流

主要有一下四種類加載器:

1. 啓動類加載器(Bootstrap ClassLoader):加載Java核心類庫[JAVA_HOME/lib];無法被直接飲用,若自定義類加載器時需要委派給啓動類加載器,則直接使用null代替

2. 擴展類加載器(extensions class loader): 加載Java 的擴展庫[JAVA_HOME/lib/ext];發者可直接使用擴展類加載器

3. 系統類加載器(system class loader):根據類路徑(CLASSPATH)加載 Java 應用的類。ClassLoader.getSystemClassLoader()來獲取

4. 用戶自定義類加載器,繼承 java.lang.ClassLoader類的方式實現

 

類加載器的雙親委派模型

層次關係:啓動類加載器--擴展類加載器---系統類加載器---自定義類加載器

  1. 某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父類加載器,依次遞歸;若父類加載不了,再返回由子類加載
  2. 優點:
    1. 使類加載器具有帶優先級的層次關係;
    2. 保證java程序穩定運行
  3. 父子關係採用組合而非繼承的方式實現

 

OSGI破壞雙親委派模型

  1. 實現代碼熱替換、模塊熱部署,想電腦插拔鼠鍵一樣
  2. OSGI實現自定義類加載機制,每一個程序模塊Bundle都有自己的類加載器,更換Bundle時連同類加載器一起替換
  3. 類加載模型爲複雜的網絡結構,當收到類加載請求時,OSGI根據網絡結構,實現自己的類搜索順序

 

類加載過程 【加載、驗證、準備、解析、初始化】

1.加載 3

  1. 通過一個類的全限定名來獲取定義此類的二進制字節流(Class文件、網絡、動態生成、數據庫等);
  2. 轉化爲方法區的運行時數據結構;【方法區沒有所以才加載類、有了就拷貝】

連接階段包括:驗證、準備、解析

2.驗證 信息

驗證字節流中的信息,符合當前虛擬機要求,不危害虛擬機安全

4個階段的檢驗動作:

  1. 文件格式驗證:字節流是否符合Class文件格式規範
  2. 元數據驗證:語義分析,保證字節流描述的信息符合Java語言規範
  3. 字節碼驗證:數據流和控制流分析,確定程序語義是合法的
  4. 符號引用驗證:確保解析動作能正確執行

 

3.準備 分配初值 方法區中

  1. 方法區中爲靜態變量分配內存,並設置初始 0 值
  2. 爲final常量賦 初始值(程序定義的值)

不包括實例變量,實例變量在對象實例化時隨着對象一起分配在堆中

例:初始值“通常情況”下是數據類型的零值,假設一個類變量的定義爲:

1

public static int value=123;

那變量value在準備階段過後的初始值爲0而不是123.把value賦值爲123的動作將在初始化階段纔會執行。

特殊情況:public static final int value=123,final修飾的常量,始化爲123

4.解析 符號引用->直接引用

  1. 虛擬機將方法區【常量池內】【符號引用】 -替換爲- 【直接引用】;多態實現
    1. 符號引用以一組 符號來描述所引用的目標;
    2. 直接引用可以是 直接指向目標的指針

解析動作主要針對類、接口、字段、類方法、接口方法、方法類型、方法句柄和調用點限定符7類符號引用進行。

5.初始化 靜態變量、靜態代碼塊、方法區存儲類信息

  1. 爲靜態變量賦程序中的值
  2. 執行static代碼塊
    1. static代碼塊只有jvm能夠調用
    2. 多線程僅允許一個線程初始化操作,其餘線程等待
  3. 類的加載順序是先加載父類後加載子類
  4. 方法區會存儲當前類信息:
    1. 包括類的靜態變量、實例變量定義、父類的類信息引用
    2. 類初始化代碼(定義靜態變量時的賦值語句 和 靜態初始化代碼塊)
    3. 實例初始化代碼(定義實例變量時的賦值語句:實例方法、構造方法)

 

6.接new過程的堆中分配內存

 

觸發條件

(1) 創建new類實例 (2) 訪問靜態變量、對靜態變量賦值 (3) 調用靜態方法 (4) 反射(如Class.forName(“com.shengsiyuan.Test”)) (5) 加載子類前,先加載父類 (6) Java虛擬機啓動時被標明爲啓動類的類(Java Test),直接使用java.exe命令來運行某個主類

 

new一個對象創建的過程 

包括5個步驟:類加載檢查過程、堆分配內存、內存初始化爲零、對象頭設置、執行對象實例方法<init>

  1. 類加載檢查過程 檢查是否能在常量池中定位到類的符號引用,無則執行類加載
    1. “new” 操作轉換爲Class文件中“new”字節碼指令
    2. 檢查指令參數是否能在常量池中定位到一個類的符號引用:
      1. 如果不能定位到,執行類加載過程;【見上面】
      2. 如果能定位到,則在堆中創建一個對象的拷貝
  2. 堆中分配內存 類加載後,Java堆分配內存
    1. 類加載完成後確定對象所需內存的大小,從Java堆分配
  3. 對象實例變量初始化,零值、null值
    1. 保證實例變量不賦初始值,也可以使用;
  4. 對象頭設置
    1. 主要設置對象頭信息,包括偏向鎖模式、對象的哈希碼、對象的GC分代年齡等(詳見下節);
  5. 執行對象實例方法<init>
    1. 實例變量賦值
    2. 構造方法
  1. memory = allocate();   //1:分配對象的內存空間  
  2. ctorInstance(memory);  //2:初始化對象  
  3. instance = memory;     //3:設置instance指向剛分配的內存地址  

 

2.3步可能會被指令重排序優化,導致單例模式出錯、加volatile

 

將方法區內的 將實例變量的定義 拷貝到堆,按照程序中定義的賦值

初始化順序是先初始化父類再初始化子類,初始化時先執行靜態代碼塊,然後是構造方法

 

String s = new String(“xyz”);產生幾個對象

先去方法區常量池中查找是否已經有了”s”對象

  1. 如果沒有則在常量池中創建一個“ s ”對象,然後堆中再創建一個常量池中此”s”對象的拷貝對象;2個對象
  2. 否則,只需要在堆中創建一個“ s ”對象

 

自定義類加載器

需要繼承java.lang.ClassLoader類,然後覆蓋它的findClass(String name)方法即可,即指明如何獲取類的字節碼流。

如果要符合雙親委派規範,則重寫findClass方法(用戶自定義類加載邏輯);要破壞的話,重寫loadClass方法(雙親委派的具體邏輯實現)

 

對象的內存佈局:對象頭、實例數據、對齊填充

  1. 對象頭信息
    1. Mark Word 6個: hash碼、GC年齡、鎖狀態標識、持有的鎖owner、偏向鎖線程ID、偏向鎖時間戳
    2. 類型指針 判斷對象屬於哪個類的實例,指向所屬類的指針,
  2. 實例數據 存儲真正有效數據
    1. 字段的分配策略:相同寬度的字段總是被分配到一起,便於之後取數據;
    2. 父類定義的變量會出現在子類前面
  3. 對齊填充 佔位符的作用,非必須

 

對象實例數據的訪問定位:

1.使用句柄地址:二次定位

java堆中將會劃出內存作爲句柄池,reference存儲句柄地址,再通過句柄中的實例數據指針,查找堆中對象實例數據

優點:對象被移動時,只改變實例數據指針(垃圾回收時)

2.直接指針訪問對象實例數據,reference中存儲的就是對象堆中的實例數據地址【類型數據都是在方法區】

優點:只進行了一次指針定位,節省了時間,而這也是HotSpot採用的實現方式;由於對象訪問比較頻繁,這個較好

 

類型數據都是通過指針二次查找,存儲在方法區

JVM優化 內存、收集器、工具

參數調優

java堆棧大小設置相關

-Xms :設置Java堆棧的初始化大小

-Xmx :設置最大的java堆大小

-XX:PermSize and MaxPermSize :設置持久帶的大小

-XX:NewRatio :設置年輕代和老年代的比值

-XX:NewSize :設置年輕代的大小

打印垃圾回收信息

verbose:gc :記錄GC運行以及運行時間,一般用來查看GC是否有瓶頸

-XX:+PrintGCDetails :記錄GC運行時的詳細數據信息,包括新生佔用的內存大小及消耗時間

-XX:-PrintGCTimeStamps :打印收集的時間戳

垃圾集器配置

-XX:+UseParallelGC :使用並行垃圾收集器

-XX:ParallelGCThreads=N,設置並行垃圾回收的線程數,此值可以設置與機器處理機數量一致(有建議core+3/4);

-XX:-UseConcMarkSweepGC :使用CMS 併發標誌掃描收集器

-XX:-UseSerialGC :使用串行垃圾收集器

配置日誌文件

-Xloggc:filename :設置GC記錄的文件

-XX:+UseGCLogFileRotation :啓用GC日誌文件的自動轉儲

-XX:GCLogFileSize=1M :控制GC日誌文件的大小

類加載和跟蹤類加載和卸載的信息【診斷內存泄露】

-XX:+TraceClassLoading :跟蹤類加載的信息

-XX:+TraceClassUnloading :跟蹤類卸載的信息

JVM性能調優工具 VisualVM、BTrace、Yslow

  1. jps(Java Virtual Machine Process Status Tool)
    1. 主要用來輸出JVM中運行的進程狀態信息
  2.  jstack(Java Stack Trace)
    1. 主要用來查看某個Java進程內的線程堆棧信息。語法格式如下:
  3. jmap(Java Memory Map)
    1. jmap用來查看堆內存使用狀況,一般結合jhat使用
  4. jhat(Java Heap Analysis Tool)
    1. 用於對Java 堆進行離線分析的工具,它可以對不同虛擬機中導出的heap信息文件進行分析
  5. jstat(Java Virtual Machine Statistics Monitoring Tool)
    1. Jstat用於監控基於HotSpot的JVM,對其堆的使用情況進行實時的命令行的統計,使用jstat我們可以對指定的JVM做如下監控:
  6. jconsole
    1. 一個java GUI監視工具,可以以圖表化的形式顯示各種數據。並可通過遠程連接監視遠程的服務器VM。用java寫的GUI程序,用來監控VM,並可監控遠程的VM,非常易用,而且功能非常強。命令行裏打 jconsole,選則進程就可以了
  7. GC日誌:內存回收的詳細情況,頻繁程度、GC導致應用停止的時間,GC的原因

 

java GC延遲問題 GC優化 原因及解決辦法

  • 詳細的 GC 日誌,查看 GC 日誌中是否出現了上述的典型內存異常問題(promotion failed, concurrent mode failure)
  • 藉助 Linux 平臺下的 iostat、vmstat、netstat、mpstat 等命令監控系統情況
  • 使用 VisualVM、GCHisto 這個 GC 圖形用戶界面工具,可以統計出 Minor GC 及 Full GC 頻率及時長分佈,可參考:http://blog.csdn.net/wenniuwuren/article/details/50760259
  • 如果程序沒問題,參數調了幾次還是不能解決,可能說明流量太大,需要加機器把壓力分散到更多 JVM 上

 

性能測試:AJmeter

SpringMVC流程

 

賬戶A轉到賬戶B,什麼流程 rollback

髒讀,不可重複讀,幻讀

介紹一下hadoop mapreduce能解決什麼問題

hadoop 海量文檔計算重複最多的詞

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章