知識點整理:
- java運行時數據區域(內存模型)
- 堆
- Enden、from survivor、to survivor
- 老年代:大對象、15輪、相同多
- 存放實例、實例變量、數組
- 方法區
- 類信息、常量池、靜態變量
- 棧 私有
- 棧幀:
- 局部變量表:局部變量---基本數據、對象引用、返回地址類型
- 操作數棧:算數運行、遞歸時的參數傳遞
- 動態鏈接:指向常量池中的符號引用,運行期間轉化爲直接引用
- 方法返回地址:
- return正常出口---恢復上一個棧幀數據、返回值入操作數棧、調用程序計數器
- 異常出口:異常處理器
- 棧幀:
- 程序計數器:字節碼指令的行號指示器、私有
- OOM:
- Java heap spacess:內存泄露【垃圾對象太多】、內存溢出
- PermGen space:類信息過多、常量過多
- stackOverflowerError:遞歸深度、死循環
- 堆
- GC 可達性分析:棧、方法區靜態、常量池引用對象
- gc機制:分代收集:新生代--複製、老年代--標記整理
- 垃圾收集器:Parallel Scavenge(old)吞吐量、CMS服務響應速度、G1
- gc觸發:minor、full觸發(空間分配擔保)
- gc過程:引用鏈OopMap、安全點、安全區
- 對象內存 對象頭、實例數據、對齊
- 訪問定位:句柄、直接指針
- new對象過程
- 類加載過程
- 類加載器:雙親委派模型
- 觸發時機:new、靜態、反射、先加載父類
jvm的內存佈局
JVM內存結構主要有三大塊:堆內存、方法區、棧
- 堆內存是JVM中最大的一塊,由年輕代和老年代組成,線程共享
-
- 年輕代內存又被分成三部分,Eden空間、From Survivor空間、To Survivor空間,默認情況下年輕代按照8:1:1的比例來分配;
- 方法區存儲類信息、常量池、靜態變量等數據,線程共享
- 棧分爲java虛擬機棧、本地方法棧,主要用於方法的執行,線程私有
爲什麼兩個倖存空間 From Survivor、To Survivor 解決碎片問題
引進了“倖存區”作用:
- 降低gc頻率,如果活着的對象全部進入老年代,老年代很快被填滿,Full GC 的頻率大大增加
- 解決碎片問題
- Eden 空間快滿時 Minor GC ,頻率得以降低
缺點:兩個 Survivor ,10%的空間浪費、複製對象開銷
機制
- 如果對象在新生代 gc 之後任然存活,暫時進入倖存區;以後每過一次 gc ,對象年齡+1,直到某個設定的值15或直到“To”區被填滿,“To”區被填滿之後,會將所有對象移動到年老代中
- 把 Eden : From Survivor : To Survivor 空間大小設成 8 : 1 : 1 ,對象總是在 Eden 區出生, From Survivor 保存當前的倖存對象, To Survivor 爲空。一次 gc 發生後:
- Eden 區活着的對象 + From Survivor 存儲的對象被複制到 To Survivor ;
- 清空 Eden 和 From Survivor ;
- 顛倒 From Survivor 和 To Survivor 的邏輯關係: From 變 To , To 變 From
介紹jvm每個區域的作用 堆、方法區、棧、程序計數器
Java堆(Heap)
- 虛擬機啓動時創建,內存中最大的一塊,線程共享
- 存放對象實例、數組、實例成員變量
- 垃圾收集器管理的主要區域,也被稱做“GC堆”,邏輯上連續,一般採用分代收集算法
方法區(Method Area)
- 線程共享,存儲已被虛擬機加載的,類加載器 加載的---
- 類信息:
- 常量池:靜態常量池:編譯期生成的字面量【final常量】和符號引用 ;運行時常量池:jvm虛擬機在完成類裝載操作後,運行期間生成的新常量
- 靜態變量、編譯器編譯後的靜態變量數據
- 即時編譯器編譯後的代碼
- 內存回收目標主要是常量池的回收和對類型的卸載
常量池的好處
常量池是爲了避免頻繁的創建和銷燬對象而影響系統性能,其實現了對象的共享
例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中
- 節省內存空間:常量池中所有相同的字符串常量被合併,只佔用一個空間
- 節省運行時間:比較字符串時,==比equals()快。對於兩個引用變量,只用==判斷引用是否相等,也就可以判斷實際值是否相等
JVM棧(JVM Stacks)
Java虛擬機棧
- 線程私有,生命週期與線程相同
- 描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作數棧、動態連接(指向常量池)、方法返回地址等信息。每一個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程
- 局部變量表:局部變量:方法參數和方法內部定義的變量,局部變量表所需的內存空間在編譯期間完成分配;【隨着方法的消失而消失】
- 編譯期可知的基本數據類型(boolean、byte、char、short、int、float、long、double)
- 對象or數組引用(作爲參數)(reference類型 指針指向,內存數據存在堆中,類型信息存儲在方法區)
- 返回地址類型(指向了一條字節碼指令的地址)
- 操作數棧:先入後出,初始爲空,在方法的執行過程中加入數據: 算術運算、方法參數、方法返回值
- 動態連接:棧幀包含的一個指針:指向運行時常量池中,所屬方法的符號引用,在運行期間將符號引用轉化爲直接引用稱爲動態鏈接
- 方法返回地址 兩種方式退出:
- 正常完成出口:是執行引擎遇到一個return的字節碼指令,恢復上層方法的局部變量表和操作數棧,把返回值壓入調用者棧幀的操作數棧中,然後調用程序計數器執行後一條指令。
- 異常完成出口:方法執行過程中遇到了異常,異常沒有在方法體內得到處理,返回地址由異常處理器確定
- 局部變量表:局部變量:方法參數和方法內部定義的變量,局部變量表所需的內存空間在編譯期間完成分配;【隨着方法的消失而消失】
本地方法棧(Native Method Stacks)
本地方法棧則是爲虛擬機使用到的Native本地方法服務
程序計數器(Program Counter Register)
- 線程私有,一塊較小的內存空間
- 當前線程所執行的字節碼指令的行號指示器
- 通過改變這個計數器的值來選取下一條字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成
- 每條線程都需要有一個獨立的程序計數器,各條線程之間的計數器互不影響
可達性分析+分代收集+回收算法
可達性分析=引用鏈枚舉 判斷一個對象是否存活、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)
- 準確式GC 快速完成GC Roots引用鏈枚舉
- 引用鏈枚舉時,應用OopMap數據結構,快速完成GC Roots引用鏈枚舉
- OopMap:在類加載完成時,存儲 :寄存器和棧的 <偏移量,數據及數據類型>;<k,v>
- 安全點檢測:程序有長時間執行特徵 --- 方法調用、循環跳轉、異常跳轉時
- 僅需在安全點記錄OopMap信息;每條指令生成OopMap,則空間成本太大;
- 程序執行時僅在安全點停下來GC
- 多線程的主動式中斷,使得各個線程都跑到安全點再停頓
- 在安全點、創建的對象分配內存時 設置一個標誌
- 各個線程執行時主動輪詢該標誌,若爲真,則中斷掛起
- 安全區域檢測:代碼中,引用關係不發生變化
- 線程沒有分配CPU時間,無法跑到安全點,導致代碼中,引用關係不發生變化
- GC時可忽略該標識自己處於安全區域的線程
- 要離開安全區域,需要收到系統已完成引用鏈枚舉的信號
java垃圾回收機制
- 自動:不需要顯示釋放對象內存,虛擬機自行執行
- GC時間:在虛擬機空閒、堆內存不足時觸發,低優先級垃圾回收線程
- GC對象:沒任何引用的對象(可達性算法)
- 方式:minorGC fullgc
java中垃圾回收的方法有哪些
- 標記-清除:x
- 標記哪些要被回收的對象,然後統一回收
- 特點:
-
-
- 標記和清除的效率低;
- 產生大量不連續的內存碎片,GC頻繁---以後程序在分配較大的對象時,由於沒有充足的連續內存導致GC頻繁
-
- 複製算法: 適合年輕代
-
- 把 Eden : From Survivor : To Survivor 空間大小設成 8 : 1 : 1 ,對象總是在 Eden 區出生,若Eden區滿,觸發minor GC
- 若GC後,存活的對象太多,to survivor內存不夠時,通過分配擔保機制複製到老年代;老年代 full gc
- 標記-整理 適合老年代
-
- 在清除對象的時候先將可回收對象移動到一端,然後清除掉端邊界以外的對象
- 解決大量內存碎片問題
- 當對象存活率較高時,效率也不差
- 在清除對象的時候先將可回收對象移動到一端,然後清除掉端邊界以外的對象
- 分代收集 綜合
-
- 根據對象的生存週期,將堆分爲新生代和老年代
- 在新生代中,對象生存期短,採用複製算法
- 老年代裏的對象存活率較高,使用標記-整理 或者 標記-清除
- 根據對象的生存週期,將堆分爲新生代和老年代
5.G1收集器的可預測停頓
Jvm對象分配方案 分代機制 何時進入老年代
對象優先在Eden分配;Eden區沒有足夠空間時,發起一次MinorGC;
- 大對象直接進入老年代;
通過 -XX:PretenureSizeThreshold參數設置;
- 長期存活的對象進入老年代:存活輪次多 15
MinorGC一次還存活在Survivor中,年齡+1; 通過 -XX:MaxTenuringThreshold參數設置;
- 年齡相同的大於一半,動態對象年齡判別:
在survivor中年齡相同的所有對象大小總和大於 survivor 一半,年齡大於或等於該年齡的對象進入老年代;防止survivor滿
- 空間(檢測)分配擔保機制:fullgc前 需要比較兩次
每次MinorGC之前,會檢查老年代最大連續可用空間是否大於 新生代所有對象的總空間,大於則表示安全,MinorGC;
如果小於:(JDK 6U24不再檢查HandlePromotionFailure,一定會冒險)
檢查HandlePromotionFailure 爲 true ,允許冒險,歷次晉升到老年代的對象平均大小與本次進入的對象大小比較,若歷次大 MinorGC,若小 FullGC;
HandlePromotionFailure 爲 false,直接進行FullGC;
簡述minor和fullgc,minorGC以及FullGC觸發條件
- 新生代進行一次垃圾清理,被稱爲minorGC
- 老年代進行一次垃圾清理,被稱爲fullGC或者majorGC。速度一般較慢
- 大多數新生對象生命週期很短,所以MinorGC通常很頻繁,回收速度也較快
- 降低MinorGC的頻率、減少fullGC的次數
觸發條件:
MinorGC:Eden區滿時觸發MinorGC;FullGC也會伴隨有MinorGC;
FullGC:a. 老年代不夠分配時,觸發FullGC;
b. 空間(檢測)分配擔保機制:MinorGC觸發前,比較老年代的剩餘空間和新生代所有對象大小,老年代小,且不允許冒險,則fullgc
允許冒險,繼續比較對象歷次平均大小與本次進入老年代的大小,若本次大,則FullGC;
爲什麼要擔保:每次minorgc,新生代年齡滿15的會進入老年代,如果新生代全部對象都一起滿15會導致老年代不夠放
c. 手動調用System.gc(),提醒JVM FullGC,但不可控;
棧溢出、堆溢出、內存溢出的原因
棧溢出的原因
- 遞歸調用
- 大量循環、死循環
- 函數體內局部變量數組過大
內存溢出的原因是什麼
- JVM沒有及時回收,堆內存泄露
- 循環或遞歸中大量的new對象,堆溢出
- 靜態變量大、類加載過多,類信息、方法區溢出
- 函數體內的數組過大,棧溢出
- 遞歸或無限遞歸,棧溢出
oom類型
導致的原因
內存溢出 out of memory,是指程序在申請內存時,沒有足夠的內存空間供其使用
內存泄漏 memory leak,是指程序在申請內存後,無法釋放已申請的內存空間,最終會導致out of memory
1,Java Heap 溢出
堆 存放對象實例和數組,線程共享;
- 內存不夠:實例過多、數組過大、大量的new對象;集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;
- 內存泄露:靜態集合類引起內存泄露;各種連接沒有關閉;單例對象持有外部對象的引用
一般的異常信息: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) 老年代 併發的標記-清除
- 初始標記(CMS initial mark)S
- 併發標記(CMS concurrent mark)
- 重新標記(CMS remark) S
- 併發清除(CMS concurrent sweep)
初始標記、重新標記:這兩個步驟仍然需要“Stop The World”【所有線程停止工作】
- 初始標記僅僅只是標記一下GC Roots能直接關聯到的對象【棧、方法區】,速度很快,要“Stop The World”
- 併發標記階段就是進行GC Roots Tracing【引用鏈跟蹤過程】的過程,剛纔產生的集合中標記出存活對象
- 重新標記階段則是爲了修正併發標記期間,因用戶程序繼續運作,而導致標記產生變動的 部分對象的標記記錄,要”Stop The World“
- 比初始標記階段稍長一些,但遠比並發標記的時間短
- 併發清理回收所有的垃圾對象,由於整個過程中耗時最長的併發標記和併發清除過程中,收集器線程都可以與用戶線程一起工作
缺點:
- CPU資源敏感(需要併發)
- 無法處理浮動垃圾(邊併發GC邊產生垃圾)
- 在默認設置下,CMS收集器在老年代使用了68%的空間後就會被激活
- 要是CMS運行期間預留的內存無法滿足程序需要,就會出現一次“Concurrent Mode Failure”失敗【運行時模式錯誤】
- 大量空間碎片(需要碎片整理)
- CMS收集器提供了一個-XX:+UseCMSCompactAtFullCollection開關參數,用於在“享受”完Full GC服務之後額外免費附送一個碎片整理過程
3.面向服務器端應用,低停頓
G1收集器
- 併發,邊GC邊執行代碼
- 分代收集:單個收集器,即可管理不同存活時間的對象
- 併發標記-整理算法,無空間碎片
- 可預測的停頓:可設定在長度爲M毫秒內,垃圾收集時間不超過N毫秒
- 實現方式:將堆劃分爲相等的region,設置一個價值標記,進行跟蹤;優先回收價值最大的region
- 價值標記:回收所獲得的空間大小和所需時間的經驗值,用優先隊列維護
初始標記 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類的方式實現
類加載器的雙親委派模型
層次關係:啓動類加載器--擴展類加載器---系統類加載器---自定義類加載器
- 某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父類加載器,依次遞歸;若父類加載不了,再返回由子類加載
- 優點:
- 使類加載器具有帶優先級的層次關係;
- 保證java程序穩定運行
- 父子關係採用組合而非繼承的方式實現
OSGI破壞雙親委派模型
- 實現代碼熱替換、模塊熱部署,想電腦插拔鼠鍵一樣
- OSGI實現自定義類加載機制,每一個程序模塊Bundle都有自己的類加載器,更換Bundle時連同類加載器一起替換
- 類加載模型爲複雜的網絡結構,當收到類加載請求時,OSGI根據網絡結構,實現自己的類搜索順序
類加載過程 【加載、驗證、準備、解析、初始化】
1.加載 3
- 通過一個類的全限定名來獲取定義此類的二進制字節流(Class文件、網絡、動態生成、數據庫等);
- 轉化爲方法區的運行時數據結構;【方法區沒有所以才加載類、有了就拷貝】
連接階段包括:驗證、準備、解析
2.驗證 信息
驗證字節流中的信息,符合當前虛擬機要求,不危害虛擬機安全
4個階段的檢驗動作:
- 文件格式驗證:字節流是否符合Class文件格式規範
- 元數據驗證:語義分析,保證字節流描述的信息符合Java語言規範
- 字節碼驗證:數據流和控制流分析,確定程序語義是合法的
- 符號引用驗證:確保解析動作能正確執行
3.準備 分配初值 方法區中
- 方法區中爲靜態變量分配內存,並設置初始 0 值
- 爲final常量賦 初始值(程序定義的值)
不包括實例變量,實例變量在對象實例化時隨着對象一起分配在堆中
例:初始值“通常情況”下是數據類型的零值,假設一個類變量的定義爲:
1 |
public static int value=123; |
那變量value在準備階段過後的初始值爲0而不是123.把value賦值爲123的動作將在初始化階段纔會執行。
特殊情況:public static final int value=123,final修飾的常量,始化爲123
4.解析 符號引用->直接引用
- 虛擬機將方法區【常量池內】【符號引用】 -替換爲- 【直接引用】;多態實現
- 符號引用以一組 符號來描述所引用的目標;
- 直接引用可以是 直接指向目標的指針
解析動作主要針對類、接口、字段、類方法、接口方法、方法類型、方法句柄和調用點限定符7類符號引用進行。
5.初始化 靜態變量、靜態代碼塊、方法區存儲類信息
- 爲靜態變量賦程序中的值
- 執行static代碼塊
- static代碼塊只有jvm能夠調用
- 多線程僅允許一個線程初始化操作,其餘線程等待
- 類的加載順序是先加載父類後加載子類
- 方法區會存儲當前類信息:
- 包括類的靜態變量、實例變量定義、父類的類信息引用
- 類初始化代碼(定義靜態變量時的賦值語句 和 靜態初始化代碼塊)
- 實例初始化代碼(定義實例變量時的賦值語句:實例方法、構造方法)
6.接new過程的堆中分配內存
觸發條件
(1) 創建new類實例 (2) 訪問靜態變量、對靜態變量賦值 (3) 調用靜態方法 (4) 反射(如Class.forName(“com.shengsiyuan.Test”)) (5) 加載子類前,先加載父類 (6) Java虛擬機啓動時被標明爲啓動類的類(Java Test),直接使用java.exe命令來運行某個主類
new一個對象創建的過程
包括5個步驟:類加載檢查過程、堆分配內存、內存初始化爲零、對象頭設置、執行對象實例方法<init>
- 類加載檢查過程 檢查是否能在常量池中定位到類的符號引用,無則執行類加載
- “new” 操作轉換爲Class文件中“new”字節碼指令
- 檢查指令參數是否能在常量池中定位到一個類的符號引用:
- 如果不能定位到,執行類加載過程;【見上面】
- 如果能定位到,則在堆中創建一個對象的拷貝
- 堆中分配內存 類加載後,Java堆分配內存
- 類加載完成後確定對象所需內存的大小,從Java堆分配
- 對象實例變量初始化,零值、null值
- 保證實例變量不賦初始值,也可以使用;
- 對象頭設置
- 主要設置對象頭信息,包括偏向鎖模式、對象的哈希碼、對象的GC分代年齡等(詳見下節);
- 執行對象實例方法<init>
- 實例變量賦值
- 構造方法
- memory = allocate(); //1:分配對象的內存空間
- ctorInstance(memory); //2:初始化對象
- instance = memory; //3:設置instance指向剛分配的內存地址
2.3步可能會被指令重排序優化,導致單例模式出錯、加volatile
將方法區內的 將實例變量的定義 拷貝到堆,按照程序中定義的賦值
初始化順序是先初始化父類再初始化子類,初始化時先執行靜態代碼塊,然後是構造方法
String s = new String(“xyz”);產生幾個對象
先去方法區常量池中查找是否已經有了”s”對象
- 如果沒有則在常量池中創建一個“ s ”對象,然後堆中再創建一個常量池中此”s”對象的拷貝對象;2個對象
- 否則,只需要在堆中創建一個“ s ”對象
自定義類加載器
需要繼承java.lang.ClassLoader類,然後覆蓋它的findClass(String name)方法即可,即指明如何獲取類的字節碼流。
如果要符合雙親委派規範,則重寫findClass方法(用戶自定義類加載邏輯);要破壞的話,重寫loadClass方法(雙親委派的具體邏輯實現)
對象的內存佈局:對象頭、實例數據、對齊填充
- 對象頭信息
- Mark Word 6個: hash碼、GC年齡、鎖狀態標識、持有的鎖owner、偏向鎖線程ID、偏向鎖時間戳
- 類型指針 判斷對象屬於哪個類的實例,指向所屬類的指針,
- 實例數據 存儲真正有效數據
- 字段的分配策略:相同寬度的字段總是被分配到一起,便於之後取數據;
- 父類定義的變量會出現在子類前面
- 對齊填充 佔位符的作用,非必須
對象實例數據的訪問定位:
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
- jps(Java Virtual Machine Process Status Tool)
- 主要用來輸出JVM中運行的進程狀態信息
- jstack(Java Stack Trace)
- 主要用來查看某個Java進程內的線程堆棧信息。語法格式如下:
- jmap(Java Memory Map)
- jmap用來查看堆內存使用狀況,一般結合jhat使用
- jhat(Java Heap Analysis Tool)
- 用於對Java 堆進行離線分析的工具,它可以對不同虛擬機中導出的heap信息文件進行分析
- jstat(Java Virtual Machine Statistics Monitoring Tool)
- Jstat用於監控基於HotSpot的JVM,對其堆的使用情況進行實時的命令行的統計,使用jstat我們可以對指定的JVM做如下監控:
- jconsole
- 一個java GUI監視工具,可以以圖表化的形式顯示各種數據。並可通過遠程連接監視遠程的服務器VM。用java寫的GUI程序,用來監控VM,並可監控遠程的VM,非常易用,而且功能非常強。命令行裏打 jconsole,選則進程就可以了
- 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 海量文檔計算重複最多的詞