學習java虛擬機
學習java虛擬機
- 1、類加載的五個過程:加載、驗證、準備、解析、初始化
- 2、類的加載器的分類
- 2.1、雙親委派機制
- 3、類的加載器的分類
- 4、Java虛擬機棧
- 5、Java本地方法棧
- 6、Java虛擬機棧
- 7、Java堆
- 8、Java方法區
- 9、Java常量池
- 10、Java對象創建步驟
- 11、Java對象的內存結果
- 12、Java訪問對象
- 13、JavaGC垃圾回收
- 13.1、引用計數法
- 13.2、Java可達性分析法
- 13.3、Java標記清除
- 13.4、Java標記復制算法(處理新生代,小部分移動大部分回收)
- 13.5、Java標記整理
- 14、JVM垃圾收集器
- 14.1、Serial收集器
- 14.2、ParNew收集器
- 14.3、Parallel Scavenge收集器
- 14.3、CMS垃圾收集器
- 14.4、G1垃圾收集器
- 15、Java內存分配
- 15.1、Java堆內存區域的劃分以及作用講解
- 15.2、Jvm大對象分配原則
- 15.3、逃逸分析和棧上分配
- 16、Java虛擬機工具
- 16.1、使用虛擬機工具jps
- 16.2、使用虛擬機工具jstat與jinfo
- 16.3、使用虛擬機工具jmap
- 16.4、使用虛擬機工具jhat
- 16.5、使用虛擬機工具jstack
- 面試題模塊
- 線程死鎖是什么?線程狀態有哪些?他們之間是怎么切換的
- 關于頻繁下載FullGC的解決方法
1、類加載的五個過程:加載、驗證、準備、解析、初始化
類的個生命周期如下圖:
-
加載:根據查找路徑找到相應的class文件,然后導入。類的加載方式分為
隱式加載和顯示加載兩種。隱式加載指的是程序在使用new關鍵詞創建對象時,會隱式的調用類的加載器把對應的類加載到jvm中。顯示加載指的是通過直接調用class.forName()方法來把所需的類加載到jvm中。 -
檢查:檢查夾加載的class文件的正確性。
-
準備;給類中的靜態變量分配內存空間。
-
解析:虛擬機將常量池中的符號引用替換成直接引用的過程。符號引用就理解為一個標示,而在直接引用直接指向內存中的地址。
-
初始化:對靜態變量和靜態代碼塊執行初始化工作。
2、類的加載器的分類
- 隔離加載類
- 修改類的加載方式
- 擴展加載源
- 防止源碼泄露
2.1、雙親委派機制
為什么要設計這種機制
這種設計有個好處是,如果有人想替換系統級別的類:String.java。篡改它的實現,在這種機制下這些系統的類已經被Bootstrap classLoader加載過了(為什么?因為當一個類需要加載的時候,最先去嘗試加載的就是BootstrapClassLoader),所以其他類加載器并沒有機會再去加載,從一定程度上防止了危險代碼的植入。
3、類的加載器的分類
棧是運行時的單位,而堆是存儲的單位
棧解決程序的運行問題,即程序如何執行,或者說如何處理數據。堆解決的是數據存儲的問題,即數據怎么放、放在哪兒。
4、Java虛擬機棧
是什么
用于作用于方法執行的一塊java內存區域
為什么
每個方法在執行的同時都會創建一個棧幀(Stack Framel)用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程
特點
局部變量表存放了編譯期可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)以及對象引用(reference類型)
如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常
5、Java本地方法棧
是什么
用于作用域本地方法執行的一塊Java內存區域什么是本地方法?
為什么
與Java虛擬機棧相同,每個方法在執行的同時都會創建一個棧幀(Stack Framel)用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程
特點
Hotshot將Java虛擬機棧和本地方法棧合二為一
6、Java虛擬機棧
是什么
程序計數器是一塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器
字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成
為什么
為了線程切換后能恢復到正確的執行位置,每條線程都需要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲,我們稱這類內存區域為"線程私有""的內存
特點
內存區域中唯一一個沒有規定任何OutOfMemoryError 情況的區域
7、Java堆
是什么
是Java內存區域中一塊用來存放對象實例的區域,幾乎所有的對象實例都在這里分配內存
為什么
此內存區域的唯一目的就是存放對象實例
Java堆(Java Heap)是Java虛擬機所管理的內存中最大的一塊Java堆是被所有線程共享的一塊內存區域
特點
Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱做"GC堆”(Garbage
Java堆可以分成新生代和老年代新生代可分為To Space、From Space、Eden
8、Java方法區
是什么
是各個線程共享的內存區域,它用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據
什么是類信息:類版本號、方法、接口
為什么
內存中存放類信息、靜態變量等數據,屬于線程共享的一塊區域
Hotspot使用永久代來實現方法區JRockit、IBM J9VM Java堆一樣管理這部分內存
特點
并非數據進入了方法區就如永久代的名字一樣"永久"存在了。這區域的內存回收目標主要是針對常量池的回收和對類型的卸載
方法區也會拋出OutofMemoryError,當它無法滿足內存分配需求時
9、Java常量池
運行時常量池的模擬
public class A {public static void main(String[] args) {String a = "abc";String b = "abc";System.out.printiln(a==b) ;//trueString c = new String("abc"); System.out.println(a==c);//false由于c內存分到到堆里,而a和b是在常量池中System.out.println(a=-c.intern());//true將c的內存移動到方法區運行時常量池中
)
是什么
運行時常量池是方法區的一部分,Class文件除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用于存放編譯器生成的各種字面量和符號引用,這部分內容將在類加載后進入方法區的運行時常量池中存放。
特點
運行時常量池是方法區的一部分,受到方法區內存的限制,當常量池再申請到內存時會拋出OutOfMemoryError異常
10、Java對象創建步驟
對象創建的流程步驟包括哪些:
虛擬機遇到一條new指令時,首先檢查這個對應的類能否在常量池中定位到一個類的符號引用
判斷這個類是否已被加載、解析和初始化
為這個新生對象在Java堆中分配內存空間,其中Java堆分配內存空間的方式主要有以下兩種
1、指針碰撞
1.1、分配內存空間包括開辟—塊內存和移動指針兩個步驟
1.2、非原子步驟可能出現并發問題,Java虛擬機采用GAS配上失敗重試的方式保證更新操作的原子性
2、空閑列表
2.1、分配內存空間包括開辟一塊內存和修改空閑列表兩個步驟
2.2、非原子步驟可能出現并發問題,Java虛擬機采用CAS配上失敗重試的方式保證更新操作的原子性
將分配到的內存空間都初始化為零值
設置對象頭相關數據
1、GC分代年齡
2、對象的哈希碼hashCode
3、元數據信息
執行對象<init>方法
11、Java對象的內存結果
對象頭用于存儲對象的元數據信息:
Mark Word部分數據的長度在32位和64位虛擬機(未開啟壓縮指針)中分別為32bit和64bit,存儲對象自身的運行時數據如哈希值等。Mark Word一般被設計為非固定的數據結構,以便存儲更多的數據信息和復用自己的存儲空間。
類型指針指向它的類元數據的指針,用于判斷對象屬于哪個類的實例。
實例數據存儲的是真正有效數據,如各種字段內容,各字段的分配策略為longs/doubles、ints,shorts/chars、bytes/boolean、oops(ordinary object pointers),相同寬度的字段總是被分配到一起,便于之后取數據。父類定義的變量會出現在子類定義的變量的前面。
對齊填充部分僅僅起到占位符的作用
12、Java訪問對象
當我們在堆上創建一個對象實例后,就要通過虛擬機棧中的reference類型數據來操作堆上的對象。現在主流的訪問方式有兩種(HotSpot虛擬機采用的是第二種)∶
1.使用句柄訪問對象。即reference中存儲的是對象句柄的地址,而句柄中包含了對象實例數據與類型數據
的具體地址信息,相當于二級指針。
2.直接指針訪問對象。即reference中存儲的就是對象地址,相當于一級指針。
對比
垃圾回收分析∶方式①當垃圾回收移動對象時,reference中存儲的地址是穩定的地址,不需要修改,僅需要修改對象句柄的地址;方式②垃圾回收時需要修改reference中存儲的地址。
訪問效率分析,l方式二優于方式一,因為方式二只進行了一次指針定位,節省了時間開銷,而這也是HotSpot采用的實現方式。
13、JavaGC垃圾回收
戰略意義 能做出一個需求的同時也要懂得其對應的戰略意義
為什么要垃圾回收?
Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程序員最頭疼的內存管理的問題迎刃而解。由于有個垃圾回收機制,Java中的對象不再有"作用域"的概念,只有對象的引用才有"作用域"。垃圾回收可以有效的防止內存泄露,有效的使用空閑的內存
垃圾回收的過程是怎樣的?
如果讓你考慮垃圾回收算法你會怎么設計
完成哪些對象回收那些對象不回收的功能需求
對象是否存活判斷
堆中每個對象實例都有一個引用計數。當一個對象被創建時,且將該對象實例分配給一個變量,該變量計數設置為1。當任何其它變量賦值為這個對象的引用時,計數加1 (a= b,則b引用的對象實例的計數器+1),但當一個對象實例的某個引用超過了生命周期或者被設置為一個新值時,對象實例的引用計數器減1。任何引用計數器為0的對象實例可以被當作垃圾收集。當一個對象實例被垃圾收集時,它引用的任何對象實例的引用計數器減1
13.1、引用計數法
優缺點
引用計數收集器可以很快的執行,交織在程序運行中。對程序需要不被長時間打斷的實時環境比較有利。
無法檢測出循環引用。如父對象有一個對子對象的引用,子對象反過來引用父對象。這樣,他們的引用計數永遠不可能為0.
13.2、Java可達性分析法
可達性分析算法的概念(又叫跟搜索法
根搜索算法是從離散數學中的圖論引入的,程序把所有的引用關系看作一張圖,從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點以后,繼續尋找這個節點的引用節點,當所有的引用節點尋找完畢之后,剩余的節點則被認為是沒有被引用到的節點,即無用的節點
java中可作為GC Root的對象有
虛擬機棧中引用的對象(本地變量表)
本地方法棧中引用的對象
方法區中靜態屬性引用的對象
方法區中常量引用的對象
13.3、Java標記清除
最基礎的收集算法是"標記-清除”(Mark-Sweep)算法,如同它的名字一樣,算法分為"標記"和“清除"兩個階段:
1.1、首先標記出所有需要回收的對象,在標記完成后統一回收所有被標記的對象,它的標記過程其實在前–節講述對象標記判定時已經介紹過了。
1.2、它的主要不足有兩個:
一個是效率問題,標記和清除兩個過程的效率都不高;
另一個是空間問題,標記清除之后會產生大量不連續的內存碎片,空間碎片太多可能會導致以后在程序運行過程中需要分配較大對象時,無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作
13.4、Java標記復制算法(處理新生代,小部分移動大部分回收)
為了解決效率問題,一種稱為“復制”"(Copying)的收集算法出現了,它將可用內存按量劃分為大小相等的兩塊,每次只使用其中的一塊
當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然后再把已使用過的內存空間一次清理掉。這樣使得每次都是對整個半區進行內存回收,內存分配時也就不用考慮內存碎片等復雜情況,只要移動堆頂指針,按順序分配內存即可,實現簡單,運行高效
現在的商業虛擬機都采用這種收集算法來回收新生代,研究表明,新生代中的對象98%是“朝生夕死""的,所以并不需要按照1:1的比例來劃分內存空間,而是將內存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。
當回收時,將Eden和Survivor中還存活著的對象一次性地復制到另外一塊Survivor空間上,最后清理掉Eden和剛才用過的Survivor空間。HotSpot 虛擬機默認Eden和Survivor的大小比例是8:1,也就是每次新生代中可用內存空間為整個新生代容量的90%(80%+10%),只有10%的內存會被"浪費"。當然,98%的對象可回收只是一般場景下的數據,我們沒有辦法保證每次回收都只有不多于10%的對象存活,當Survivor空間不夠用時,需要依賴其他內存(這里指老年代)進行分配擔保(Handle Promotion)。
13.5、Java標記整理
標記整理算法解決了什么問題
復制收集算法在對象存活率較高時就要進行較多的復制操作,效率將會變低。更關鍵的是,如果不想浪費50%的空間,就需要有額外的空間進行分配擔保,以應對被使用的內存中所有對象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法
標記-整理
根據老年代的特點,有人提出了另外一種"標記-整理(Mark-Compact)算法,標記過程仍然與“標記-清除"算法一樣,但后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存
分代收集
一般把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點采用最適當的收集算法
在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行分配擔保,就必須使用"標記-清理"或者"標記一整理"算法來進行回收
14、JVM垃圾收集器
14.1、Serial收集器
是什么
收集算法是內存收到的方法論,垃圾回收器是內存回收的具體實現。
Serial是一個單線程的垃圾收集器
特點
“Stop The World”,它進行垃圾收集時,必須暫停其他所有的工作線程,直到它收集結束。在用戶不可見的情況下把用戶正常工作的線程全部停掉
14.2、ParNew收集器
是什么
ParNew收集器其實就是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集之外,其余行為包括Serial 收集器可用的所有控制參數(例如:-XX: SurvivorRatio、-XX: PretenureSize’ Threshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、對象分配規則、回收策略等都與Serial 收集器完全一樣,在實現上,這兩種收集器也共用了相當多的代碼
特點
ParNew收集器除了多線程收集之外,其他與Serial 收集器相比并沒有太多創新之處,但它卻是許多運行在Server模式下的虛擬機中首選的新生代收集器,其中有一個與性能無關但很重要的原因是,除了Serial 收集器外,目前只有它能與CMS 收集器配合工作。
使用-XX: ParallelGCThreads參數來限制垃圾收集的線程數
多線程操作存在上下文切換的問題,所以建議將-XX: ParallelGCThreads設置成和CPU核數相同,如果設置太多的話就會產生上下文切換消耗
并發與并行的概念講解
并行(Parallel)∶指多條垃圾收集線程并行工作,但此時用戶線程仍然處于等待狀態。
并發(Concurrent)︰指用戶線程與垃圾收集線程同時執行(但不一定是并行的,可能會交替執行),用戶程序在繼續運行,而垃圾收集程序運行于另一個CPU上
14.3、Parallel Scavenge收集器
是什么
Parallel Scavenge 收集器是一個新生代收集器,它也是使用復制算法的收集器,又是并行的多線程收集器
由于與吞吐量關系密切,Parallel Scavenge 收集器也經常稱為"吞吐量優先"收集器
吞吐量是什么? CPU用于運行用戶代碼的時間與CPU總時間的比值,99%時間執行用戶線程,1%時間回收垃圾,這時候吞吐量就是99%
特點
Parallel Scavenge 收集器的特點是它的關注點與其他收集器不同,CMS等收集器的關注點是盡可能地縮短垃圾收集時用戶線程的停頓時間,而Parallel Scavenge 收集器的目標則是達到個可控制的吞吐
(Throughput)。所謂吞吐量就是CPU用于運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),虛擬機總共運行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%停頓時間越短就越適合需要與用戶交互的程序,良好的響應速度能提升用戶體驗,而高吞吐量則可以高效率地利用CPU時間,盡快完成程序的運算任務,主要適合在后臺運算而不需要太多交互的任務。
虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或者最大的吞吐量,這種調節方式稱為GC自適應調節策略
-XX:MaxGCPauseMillis參數GC停頓時間,50OMB ——>300MB,這個參數配置太小的話會發生頻繁GC
-XX:GCTimeRatio參數,99%
Serial old收集器,它是一個單線程收集器,使用"標記–整理"算法
Parrallel old收集器Parallel Scavenge收集器的老年代版本,使用多線程+標記整理算法
14.3、CMS垃圾收集器
是什么
CMS (Concurrent Mark Sweep)收集器是-種以獲取最短回收停頓時間為目標的收集器。
目前很大一部分的Java應用集中在互聯網站或者B/S系統的服務端上,這類應用尤其重視服務的響應速度,希望系統停頓時間最短,以給用戶帶來較好的體驗。
CMS 收集器是基于“標記-清除"算法實現的
步驟流程
初始標記(CMS initial mark)----標記一下 GC Roots能直接關聯到的對象,速度很快
并發標記(CMS concurrent mark -…----并發標記階段就是進行GC RootsTracing 的過程
重新標記(CMS remark) -.-…-為了修正并發標記期間因用戶程序導致標記產生變動的標記記錄
并發清除(CMS concurrent sweep)
CMS垃圾收集器缺點
對CPU資源非常敏感
無法處理浮動垃圾,程序在進行并發清除階段用戶線程所產生的新垃圾
標記-清除暫時空間碎片
14.4、G1垃圾收集器
是什么
G1是一款面向服務端應用的垃圾收集器
特點
G1中每個Region都有一個與之對應的Remembered Set,當進行內存回收時,在GC根節點的枚舉范圍中加入Remembered Set即可保證不對全堆掃描也不會有遺漏﹐檢查Reference引用的對象是否處于不同的Region
G1收集器的運作大致可劃分為以下幾個步驟
初始標記(Initial Marking) --標記一下GC Roots能直接關聯到的對象
并發標記(Concurrent Marking)—從GC Root開始對堆中對象進行可達性分析,找出存活的對象,這階段耗時較長,但可與用戶程序并發執行
最終標記(Final Marking)–為了修正在并發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分標記記錄。虛擬機將這段時間對象變化記錄在線程Remembered Set Logs里面,最終標記階段需要把Remembered Set Logs的數據合并到Remembered Set中
篩選回收(Live Data Counting and Evacuation)
G1的優勢有哪些
空間整合:基于"標記一整理"算法實現為主和Region之間采用復制算法實現的垃圾收集
可預測的停頓:這是G1相對于CMS的另一大優勢,降低停頓時間是G1和CMS共同的關注點,但G1除了追求低停頓外,還能建立可預測的停頓時間模型
在G1之前的其他收集器進行收集的范圍都是整個新生代或者老年代,而G1不再是這樣。使用G1收集器時,Java堆的內存布局就與其他收集器有很大差別,它將整個Java雄劃分為多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代不再是物理隔高的了,它們都是一部分Region(不需要連續)的集合。
G1收集器之所以能建立可預測的停頓時間模型,是因為它可以有計劃地避免在整個Java堆中進行全區域的垃圾收集。G1跟蹤各個Regions里面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在后臺維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的Region (這也就是Garbage-Firsti名稱的來由)。這種使用Region劃分內存空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間內可以獲取盡可能高
15、Java內存分配
15.1、Java堆內存區域的劃分以及作用講解
對象分配的規則有哪些
對象主要分配在新生代的Eden區上
如果啟動了本地線程分配緩沖,將按線程優先在TLAB上分配
少數情況下也可能會直接分配在老年代中
GC參數指定垃圾回收
-Xms20 M、-Xmx20 M、-Xmn1 0M這3個參數限制了Java堆大小為20 MB,不可擴展,其中10 MB分配給新生代,剩下的10MB分配給老年代。-Xx: SurvivorRatio=8決定了新生代中Eden 區與兩個Survivor區的空間比例是8:1
新生代與老年代
新生代GC(Minor GC)∶指發生在新生代的垃圾收集動作,因為Java對象大多都具備朝生夕滅的特性,所以Minor GC非常頻繁,一般回收速度老年代 GC(Major GC/ Full GC)∶指發生在老年代的GC,出現了Major GC,經常會伴隨至少一次的Minor GC(但非絕對的,在 Parallel Scavenge 收集器的收集策略里就有直接進行Major GCE的策略選擇過程)。Major GCl的速度一般會比 Minor Gct慢10倍以上。
15.2、Jvm大對象分配原則
是什么
所謂的大對象是指,需要大量連續內存空間的Java對象,最典型的大對象就是那種很長的字符串以及數組
虛擬機提供了一個-XX: PretenureSizeThreshold參數,令大于這個設置值的對象直接在老年代分配。這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的內存復制
實戰代碼演練大對象配置
-verbose:gc -XX:+PrintGCDetails開啟GC日志打印
-Xms20 M設置JVM初始內存為20M
-Xmx20 M設置JVM最大內存為20M
-Xmn10 M設置年輕代內存大小為10M
15.3、逃逸分析和棧上分配
逃逸分析
逃逸分析的基本行為就是分析對象動態作用域:當一個對象在方法中被定義后,它可能被外部方法所引用,稱為方法逃逸。甚至還有可能被外部線程訪問到,譬如賦值給類變量或可以在其他線程中訪問的實例變量,稱為線程逃逸
棧上分配
棧上分配就是把方法中的變量和對象分配到棧上,方法執行完后自動銷毀,而不需要垃圾回收的介入,從而提高系統性能。
-XX:+DoEscapeAnalysis開啟逃逸分析(jdk1.8默認開啟,其它版本未測試)
-XX :-DoEscapeAnalysis關閉逃逸分析
兩種逃逸的舉例
JDK1.8默認開啟逃逸分析
public class TestEscape{public static 0bject obj ;public void variableEscape(){obj = new 0bject(); //發生逃逸)public Object methodEscape(){return new Object(); //方法逃逸}public static void alloc()ibyte[] b = new byte[2];b[0]=1;)public static void main(String[] args){long start =System.currentTimeMillis();for (int i =0; i < 108080880 ; i++) {alloc();}long end = System.currentTimeMillis();System.out.println(end-start);))
16、Java虛擬機工具
16.1、使用虛擬機工具jps
16.2、使用虛擬機工具jstat與jinfo
16.3、使用虛擬機工具jmap
16.4、使用虛擬機工具jhat
16.5、使用虛擬機工具jstack
面試題模塊
線程死鎖是什么?線程狀態有哪些?他們之間是怎么切換的
線程死鎖是什么
線程死鎖是指由于兩個或者多個線程互相持有對方所需要的資源,導致這些線程處于等待狀態,無法前往執行
Blocked狀態與Waiting狀態的區別
WAITING狀態屬于主動地顯式地申請的阻塞,BLOCKED 則屬于被動的阻塞
線程狀態分類
NEW
RUNNABLE
BLOCKED 一個正在阻塞等待一個監視器的線程處于這一狀態
WAITING一個正在無限期等待另一個線程執行一個特別的動作的線程處于這一狀態
TIMED_WAITING一個正在限時等待另一個線程執行一個動作的線程處于這一狀態
TERMINATED
關于頻繁下載FullGC的解決方法
FullGC與MinorGC講解
本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處:https://dhexx.cn/hk/18411.html
如若內容造成侵權/違法違規/事實不符,請聯系我的編程經驗分享網進行投訴反饋,一經查實,立即刪除!