你們好,我是小菜,一個渴望在互聯網行業作到蔡不菜的小菜。可柔可剛,點贊則柔,白嫖則剛!
死鬼~看完記得給我來個三連哦!java
「本文主要介紹
JVM和GC解析
若有須要,能夠參考
若有幫助,不忘 點贊 ❥linux創做不易,白嫖無義!ios
public static void main(String[] args) {
stackOverflowError(); //Exception in thread "main" java.lang.StackOverflowError
}
private static void stackOverflowError() {
stackOverflowError();
}
複製代碼
public static void main(String[] args) {
String str = "cbuc";
for (; ; ) {
str += str + UUID.randomUUID().toString().substring(0,5); //+= 不斷建立對象
}
}
複製代碼
程序在垃圾回收上花費了98%的時間,卻收集不會2%的空間。
假如不拋出GC overhead limit
,會形成:算法
ByteBuffer
來讀取或者寫入數據,這是一種基於通道(Channel)
和緩衝區(Buffer)
的 I/O 方式,它可使用Native
函數庫直接分配堆外內存,而後經過一個存儲在Java 堆裏面的DirectByteBuffer
對象做爲這塊內存的引用進行操做。這樣能在一些場景中顯著提升性能,由於避免了在Java堆和Native堆中來回複製數據。ByteBuffer.allocate(capability)
:這一種方式是分配JVM堆內存,屬於GC管轄範圍,因爲須要拷貝因此速度相對較慢。服務器
ByteBuffer.allocateDirect(capability):
這一種方式是分配OS本地內存,不屬於GC管轄範圍,因爲不須要內存拷貝,因此速度相對較快。markdown
可是若是不斷分配本地內存,堆內存不多使用,那麼JVM就不須要執行GC
,DirectByteBuffer
對象就不會被回收,這時候堆內存充足,但本地內存可能就已經使用光了,再次嘗試分配本地內存就會出現OutOfMemeoryError
,那程序就直接奔潰了。網絡
public static void main(String[] args) {
/**
* 虛擬機配置參數
* -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
*/
System.out.println("配置的maxDirectMemeory:"+ (sun.misc.VM.maxDirectMemory()/(double)1024/1024)+"MB");
try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}
// -XX:MaxDerectMemorySize=5m 配置爲5m, 這個時候咱們使用6m
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6*1024*1024);
}
複製代碼
OutOfMemeoryError:unable to create new native thread
高併發請求服務器時,常常會出現該異常
致使緣由:多線程
linux
系統默認容許的那個進程能夠建立的線程數時1024
個,你的應用建立超過這個數量就會報OutOfMemeoryError:unable to create new native thread
解決辦法:併發
linux
系統默認1024
個線程的限制,能夠經過修改linux
服務器配置,擴大linux
默認限制public static void main(String[] args) {
for (int i = 1; ; i++) {
System.out.println("輸出 i: " + i);
new Thread(()->{
try {TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}
},"線程"+i).start();
}
}
複製代碼
Java 8以後的版本使用Metaspace來替代永久代Metaspace
是方法區在HotSpot
中的實現,它與持久帶最大的區別在於:Metespace
並不在虛擬機內存中而是使用本地內存
永久代(java8 後被原空間Metaspace取代了)存放了如下信息:app
GC算法(引用計數/複製/標清/標整)是內存回收的方法,垃圾收集器就是算法的實現
目前爲止尚未完美的收集器出現,更加沒有萬能的收集器,只是針對具體應用最合適的收集器,進行分代收集
它爲單線程環境設計而且只是用一個線程進行垃圾回收,會暫停全部的用戶線程。因此不適合服務器環境。
多個垃圾回收線程並行工做,此時用戶線程是暫停的,適用於科學計算/大數據處理等弱交互場景
用戶線程和垃圾收集線程同時執行(不必定是並行,可能交替執行),不須要停頓用戶線程,適用於對響應時間有要求的場景
G1垃圾回收器將堆內存分割成不一樣的區域而後併發的對其進行垃圾回收
java -XX:+PrintCommandLineFlags -version
UseSerialGC
UseParallelGC
UseConcMarkSweepGC
UseParNewGC
UseParallelOldGC
UseG1GC
最穩定以及效率高的收集器,只使用一個線程去回收但其在進行垃圾手機過程當中可能會產生較長的停頓(「Stop-The-World」狀態)。雖然在收集垃圾過程當中須要暫停全部其餘的工做線程,可是它簡單高效,對於限定單個CPU環境來講,==沒有線程交互的開銷能夠得到更高的單線程垃圾收集效率,== 所以Serial垃圾收集器依然是Java虛擬機運行在Client 模式下默認的新生代垃圾收集器。
JVM設置參數:-XX:+UseSerialGC
開啓後會使用:Serial(Young區用)+Serial Old(Old區用的)收集器組合
,
表示:
新生代、老年代都會使用串行回收收集器,新生代使用複製算法,老年代使用標記-整理算法
使用多線程進行垃圾回收,在垃圾收集時,會Stop-The-World暫停其餘全部工做的線程知道它收集結束
ParNew
收集器其實就是Serial收集器新生代的並行多線程版本,最多見的應用場景是配合老年代的CMS GC
工做,其他的行爲和Serial收集器徹底同樣,ParNew
垃圾收集器在垃圾收集過程當中一樣也要暫停全部的工做線程。它是不少java虛擬機運行在Server模式下新生代的默認垃圾收集器。
JVM設置參數:
XX:+UseParNewGC
啓用 ParNew收集器,隻影響新生代的收集,不影響老年代。開啓上述參數後,會使用:ParNew (新生代區用)+Serial Old(老年代區用)策略
,新生代使用複製算法,老年代使用標記-整理算法。
並行回收GC(Parallel)/(Parallel Scavenge)
Parallel Scavenge
收集器相似ParNew
也是新生代垃圾收集器,使用複製算法,也是一個並行的多線程的垃圾收集器,俗稱吞吐量優先收集器。串行收集器在新生代和老年代的並行化
關注點:
可控制的吞吐量
自適應調節策略也是ParallelScavenge收集器與ParallelNew收集器的一個重要區別
JVM設置參數-XX:UseParallelGC
或 -XX:UseParallelOldGC
(可互相激活),開啓後:新生代使用複製算法,老年代使用標記-整理算法。
Parallel Scavenge
收集器搭配使用。(Parallel Scavenge+Serial Old
)並行GC(Parallel Old)/(Parallel MSC)Parallel Old
收集器是Parallel Scavenge
的老年代版本,使用多線程的標記-整理算法,Parallel Old在JDK 1.6以前,新生代使用 ParallelScavenge
收集器,只能保證新生代的吞吐量優先,沒法保證總體的吞吐量。在JDK1.6以前(Parallel Scavenge+Serial Old
)Parallel Old
正是爲了在年老代一樣提供吞吐量優先的垃圾收集器,若是系統對吞吐量要求比較高,JDK1.8 後能夠優先考慮新生代Parallel Scavenge
和年老代 Parallel Old
收集器的搭配策略。
JVM設置參數:-XX:+UseParallelOldGC
開啓 Parallel Old收集器,設置該參數後,使用 新生代Parallel + 老年代Parallel Old
策略
併發標記清除GC(CMS)
優勢:
併發收集低停頓
缺點:
併發執行,對CPU資源壓力大
:
因爲併發進行,CMS在收集與應用線程會同時會增長對堆內存的佔用,也就是說,CMS必需要在老年代堆內存用盡以前完成垃圾回收,不然CMS回收失敗時,將觸發擔保機制,串行老年代收集器將會以STW的方式進行一次GC,從而形成較大停頓時間。
採用的標記清除算法會致使大量碎片
:
標記清除算法沒法整理空間碎片,老年代空間會隨着應用時長被逐步耗盡,隨後將不得不經過擔保機制對堆內存進行壓縮。CMS也提供了參數-XX:CMSFulllGCsBeForeCompaction
(默認0,即每次都進行內存整理)來指定多少次CMS收集以後,進行一次壓縮的Full GC。
關鍵4步:
Initial Mark (初始標記)
:標記GC Root能夠直達的對象,耗時短。
Concurrent Mark(並行標記)
:從第一步標記的對象出發,併發地標記可達對象。
Remark(從新標記)
: 從新進行標記,修正Concurrent Mark期間因爲用戶程序運行而致使對象間的變化及新建立的對象,耗時短。
Concurrent Sweep(並行回收)
: 並行地進行無用對象的回收。
-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:+UseConcMarkSweepGC
-XX:+ParNewGC
之前垃圾收集器的特色:
Garbage-First
收集器,是一款面向服務端應用的收集器,優勢以下:
G1收集器的設計目標是取代CMS收集器
Stop-The-World (STW)
更可控,G1在停頓時間上添加了預測機制,用戶能夠指按期望停頓時間主要改變是Eden
,Survivor
和Tenured
等內存區域再也不是連續的了,而是變成了一個個大小同樣的region
,每一個region
從1M
到32M
不等。一個region
有可能屬於Eden
,Survivor
或者Tenured
內存區域。
STW
「(1)Region區域化垃圾收集器·
區域化內存劃片Region,總體編爲了一下列不連續的內存區域,避免了全內存區的GC操做。
核心思想:
將整個堆內存區域分紅大小相同的子區域(Region
),在JVM啓動時會自動配置這些子區域的大小。
在堆的使用上,G1並不要求對象的存儲必定是物理上連續的只要邏輯上連續便可,每一個分區也不會固定地爲某個代服務,能夠按需在年輕代和老年代之間切換。啓動時能夠經過參數-XX:G1HeapRegionSize=n
可指定分區大小(1MB~32MB
,且必須是2的冪),默認將整堆劃分爲2048
個分區。
大小範圍在1MB~32MB
,最多能設置2048
個區域,也即可以支持的最大內存爲:32MB*2048=65536MV=64G
內存
最大好處就是化整爲零,避免全內存掃描,只須要按照區域來進行掃描便可
「(2)回收步驟
針對Eden區進行收集,Eden區耗盡後會被觸發,主要是小區域收集+造成連續的內存塊,避免內存碎片
Eden
區的數據移動到新的Survivor
區,部分數據晉升到Old
區。Survivor
區的數據移動到新的Survivor
區,部分數據晉升到Old
區。「(3)執行四步
初始標記:
只標記GC Roots
能直接關聯到的對象
併發標記:
進行GC Roots Tracing
的過程
最終標記:
修正併發標記期間,因程序運行致使標記發生變化的那一部分對象
篩選回收:
根據時間來進行價值最大化的回收
「(4)經常使用配置參數
-XX:+UseG1GC
-XX:G1HeapRegionSize=n
-XX:MaxGCPauseMillis=n
-XX:InitiatingHeapOccupancyPercent=n
-XX:ConcGCThreads=n
-XX:G1ReservePercent=n
「(5)與CMS相比的優點
「(6)總結
top
17:16:47:
當前時間
up 23:47:
系統運行時間
2 users:
當前登陸用戶數
load average:0.21,0.27,0.19:
系統負載,既任務隊列的平均長度,三個數值分別爲1分鐘、5分鐘、15分鐘前到如今的平均值
1)vmstat
vmstat -n 2 3
procs
cpu
2)mpstat
mpstat -P ALL 2
查看CPU核信息
3)pidstat
pidstat -u 1 -p 進程號
每一個進程使用cpu的用量分解信息
free
應用程序中可用內存 / 系統物理內存>70%:內存充足
應用程序可用內存/系統物理內存<20% 內存不足:須要增長內存
20%<應用程序可用內存/系統物理內存<70%: 內存基本夠用
df
查看磁盤剩餘空閒數
iostat -xdk 2 3
先用top
命令找出CPU佔比最高的
ps -ef
或者 jps
進一步定位,得知是一個怎樣的後臺程序
定位到具體線程或者代碼ps -mp 進程 ==-o== THREAD,tid,time
-o
:該參數是用戶自定義格式-p
:pid進程使用cpu的時間-m
: 顯示全部線程
將須要的線程ID轉換爲16進制格式(英文小寫格式)
再使用:printf "%x/\n" 有問題的線程ID
jstat 進程ID | grep tid(16進制線程ID小寫英文)
jps
虛擬機進程情況工具
jinfo
Java配置信息工具
jmap
內存映像工具
jstat
統計信息監控工具
「今天的你多努力一點,明天的你就能少說一句求人的話!
我是小菜,一個和你一塊兒學習的男人。
💋