Java垃圾回收算法及GC觸發(fā)條件解讀
一、引言
在Java編程語言的發(fā)展歷程中,內(nèi)存管理一直是其核心特性之一。與C/C++等需要手動(dòng)管理內(nèi)存的語言不同,Java通過自動(dòng)垃圾回收(Garbage Collection,簡稱GC)機(jī)制,極大地減輕了開發(fā)人員的負(fù)擔(dān),提高了開發(fā)效率,同時(shí)也降低了內(nèi)存泄漏和懸掛指針等常見問題的發(fā)生概率。
Java的垃圾回收機(jī)制能夠自動(dòng)識(shí)別和回收不再使用的內(nèi)存空間,使得開發(fā)人員可以更加專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),而不必過多關(guān)注內(nèi)存管理的細(xì)節(jié)。然而,垃圾回收并非沒有代價(jià)。它會(huì)消耗系統(tǒng)資源,可能導(dǎo)致程序執(zhí)行暫停(Stop-The-World),影響程序的實(shí)時(shí)性能。因此,理解Java垃圾回收的原理、算法和觸發(fā)條件,對(duì)于開發(fā)高性能、低延遲的Java應(yīng)用程序至關(guān)重要。
二、Java垃圾回收基礎(chǔ)
2.1 什么是垃圾回收
垃圾回收是一種自動(dòng)內(nèi)存管理機(jī)制,它能夠識(shí)別程序中不再使用的內(nèi)存空間(即"垃圾"),并將其回收以供后續(xù)使用。在Java中,開發(fā)者不需要顯式地釋放內(nèi)存,JVM會(huì)自動(dòng)完成這一工作。
Java垃圾回收的核心任務(wù)是確定哪些對(duì)象是"活動(dòng)的"(仍在使用中),哪些是"垃圾"(不再使用)。一般來說,如果一個(gè)對(duì)象不能通過任何引用鏈從程序的"根"(如全局變量、當(dāng)前執(zhí)行棧中的局部變量等)訪問到,那么這個(gè)對(duì)象就被認(rèn)為是垃圾,可以被回收。
2.2 垃圾回收的目標(biāo)與挑戰(zhàn)
Java垃圾回收的主要目標(biāo)是:
- 自動(dòng)識(shí)別并回收不再使用的內(nèi)存,防止內(nèi)存泄漏。
- 避免懸掛指針和非法內(nèi)存訪問,提高程序的穩(wěn)定性。
- 減輕開發(fā)者的負(fù)擔(dān),提高開發(fā)效率。
- 優(yōu)化內(nèi)存使用,提高程序性能。
然而,垃圾回收也面臨著一系列挑戰(zhàn):
- 性能開銷:垃圾回收過程會(huì)消耗CPU資源,可能導(dǎo)致程序暫停(Stop-The-World),影響用戶體驗(yàn)。
- 內(nèi)存碎片:某些垃圾回收算法可能導(dǎo)致內(nèi)存碎片,降低內(nèi)存利用率。
- 不確定性:垃圾回收的時(shí)機(jī)和持續(xù)時(shí)間通常難以預(yù)測,這對(duì)實(shí)時(shí)系統(tǒng)是一個(gè)挑戰(zhàn)。
- 資源限制:在資源受限的環(huán)境(如嵌入式系統(tǒng))中,垃圾回收的開銷可能過大。
2.3 垃圾回收的性能指標(biāo)
評(píng)價(jià)Java垃圾回收算法的性能通常使用以下幾個(gè)指標(biāo):
- 吞吐量:指應(yīng)用程序運(yùn)行時(shí)間與總時(shí)間(應(yīng)用程序運(yùn)行時(shí)間+垃圾回收時(shí)間)的比值。高吞吐量意味著垃圾回收占用的時(shí)間較少,應(yīng)用程序能夠更多地利用CPU資源。吞吐量 = 應(yīng)用程序運(yùn)行時(shí)間 / (應(yīng)用程序運(yùn)行時(shí)間 + 垃圾回收時(shí)間)
- 最大暫停時(shí)間:指垃圾回收導(dǎo)致應(yīng)用程序暫停的最長時(shí)間。低暫停時(shí)間對(duì)于交互式應(yīng)用和實(shí)時(shí)系統(tǒng)尤為重要,因?yàn)殚L時(shí)間的暫停會(huì)導(dǎo)致用戶感知到明顯的卡頓。
- 堆使用效率:指應(yīng)用程序能夠有效利用的堆內(nèi)存比例。某些垃圾回收算法(如復(fù)制算法)需要預(yù)留部分內(nèi)存空間,降低了堆使用效率。
- 訪問的局部性:指程序訪問內(nèi)存的模式。良好的局部性意味著相關(guān)的對(duì)象在內(nèi)存中彼此靠近,這有助于提高緩存命中率,提升程序性能。某些垃圾回收算法能夠重新組織內(nèi)存中的對(duì)象,改善訪問局部性。
不同的垃圾回收算法在這些指標(biāo)上各有優(yōu)劣,沒有一種算法能夠在所有指標(biāo)上都表現(xiàn)最佳。因此,現(xiàn)代JVM通常會(huì)提供多種垃圾回收器,允許用戶根據(jù)應(yīng)用場景和需求進(jìn)行選擇。
三、Java主流垃圾回收算法詳解
3.1 標(biāo)記清除算法
標(biāo)記清除(Mark-Sweep)算法是最基礎(chǔ)的垃圾回收算法之一,它通過標(biāo)記活動(dòng)對(duì)象和清除非活動(dòng)對(duì)象兩個(gè)階段來完成垃圾回收。
3.1.1 原理與實(shí)現(xiàn)
標(biāo)記清除算法的工作流程分為兩個(gè)階段:
- 標(biāo)記階段:從程序的"根"出發(fā),沿著引用鏈遞歸地標(biāo)記所有可達(dá)對(duì)象為"活動(dòng)"。
- 清除階段:遍歷整個(gè)堆,回收所有未被標(biāo)記為"活動(dòng)"的對(duì)象。
在標(biāo)記階段,垃圾回收器從根對(duì)象(如全局變量、當(dāng)前執(zhí)行棧中的局部變量等)開始,沿著引用鏈遞歸地訪問所有可達(dá)對(duì)象,并將它們標(biāo)記為"活動(dòng)"。
在清除階段,垃圾回收器遍歷整個(gè)堆,將所有未被標(biāo)記的對(duì)象視為垃圾,并回收它們占用的內(nèi)存空間。
3.1.2 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 相對(duì)簡單,容易實(shí)現(xiàn)。
- 不需要額外的空間來復(fù)制對(duì)象。
- 可以處理循環(huán)引用問題。
缺點(diǎn):
- 標(biāo)記和清除階段都需要遍歷整個(gè)堆,效率較低。
- 清除階段會(huì)產(chǎn)生內(nèi)存碎片,降低內(nèi)存利用率。
- 在標(biāo)記和清除階段,程序通常需要暫停執(zhí)行(Stop-The-World),導(dǎo)致較長的暫停時(shí)間。
3.1.3 內(nèi)存碎片問題
標(biāo)記清除算法的一個(gè)主要缺點(diǎn)是會(huì)產(chǎn)生內(nèi)存碎片。
當(dāng)對(duì)象被回收后,堆中會(huì)出現(xiàn)不連續(xù)的空閑內(nèi)存塊,這些碎片可能無法滿足大對(duì)象的分配需求,即使總的空閑內(nèi)存足夠。
為了解決這個(gè)問題,一些垃圾回收器會(huì)在清除階段后進(jìn)行內(nèi)存整理(Compaction),將存活對(duì)象移動(dòng)到堆的一端,使空閑內(nèi)存形成連續(xù)的塊。這就引出了標(biāo)記整理算法。
3.2 標(biāo)記整理算法
標(biāo)記整理(Mark-Compact)算法是標(biāo)記清除算法的改進(jìn)版,它在標(biāo)記階段后增加了一個(gè)整理階段,解決了內(nèi)存碎片問題。
3.2.1 原理與實(shí)現(xiàn)
標(biāo)記整理算法的工作流程分為三個(gè)階段:
- 標(biāo)記階段:與標(biāo)記清除算法相同,從程序的"根"出發(fā),標(biāo)記所有可達(dá)對(duì)象為"活動(dòng)"。
- 整理階段:將所有存活對(duì)象移動(dòng)到堆的一端,使它們緊密排列。
- 清除階段:清除所有未被標(biāo)記的對(duì)象,回收內(nèi)存空間。
在整理階段,垃圾回收器將所有存活對(duì)象移動(dòng)到堆的一端,使它們緊密排列,從而消除內(nèi)存碎片。
這一過程需要更新所有指向這些對(duì)象的引用,確保它們指向?qū)ο蟮男挛恢谩?/p>
3.2.2 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 解決了內(nèi)存碎片問題,提高了內(nèi)存利用率。
- 可以處理循環(huán)引用問題。
- 整理后的內(nèi)存分配更加高效,不需要復(fù)雜的內(nèi)存分配算法。
缺點(diǎn):
- 整理階段需要移動(dòng)對(duì)象并更新引用,增加了垃圾回收的開銷。
- 在標(biāo)記、整理和清除階段,程序通常需要暫停執(zhí)行,導(dǎo)致較長的暫停時(shí)間。
- 對(duì)于大型堆,整理階段的開銷可能很大。
3.2.3 與標(biāo)記清除的比較
相比于標(biāo)記清除算法,標(biāo)記整理算法的主要優(yōu)勢在于解決了內(nèi)存碎片問題,提高了內(nèi)存利用率和分配效率。然而,這是以增加垃圾回收開銷為代價(jià)的,特別是在大型堆中,整理階段可能需要移動(dòng)大量對(duì)象,導(dǎo)致較長的暫停時(shí)間。
在Java的HotSpot VM中,標(biāo)記整理算法通常用于老年代(存活時(shí)間較長的對(duì)象所在的內(nèi)存區(qū)域),因?yàn)槔夏甏膶?duì)象通常存活率較高,內(nèi)存碎片問題更為嚴(yán)重。而對(duì)于新生代(存活時(shí)間較短的對(duì)象所在的內(nèi)存區(qū)域),通常使用復(fù)制算法,因?yàn)樾律膶?duì)象大多數(shù)都是短暫的,存活率較低。
3.3 復(fù)制算法
復(fù)制(Copying)算法是一種高效的垃圾回收算法,特別適用于新生代對(duì)象的回收。
它通過將內(nèi)存分為兩個(gè)相等的區(qū)域,每次只使用其中一個(gè)區(qū)域,在垃圾回收時(shí)將存活對(duì)象復(fù)制到另一個(gè)區(qū)域,從而實(shí)現(xiàn)內(nèi)存的回收和整理。
3.3.1 原理與實(shí)現(xiàn)
復(fù)制算法的工作流程如下:
- 將可用內(nèi)存分為兩個(gè)大小相等的區(qū)域,稱為"From空間"和"To空間"。
- 程序只在"From空間"分配對(duì)象。
- 當(dāng)"From空間"用盡時(shí),觸發(fā)垃圾回收。
- 垃圾回收器從根對(duì)象開始,標(biāo)記所有可達(dá)對(duì)象,并將它們復(fù)制到"To空間",同時(shí)更新引用。
- 復(fù)制完成后,"From空間"中的所有對(duì)象都被視為垃圾,整個(gè)"From空間"被清空。
- 交換"From空間"和"To空間"的角色,繼續(xù)運(yùn)行程序。
在HotSpot VM中,新生代的復(fù)制算法采用了一種稱為"半空間復(fù)制"的變種。
它將新生代內(nèi)存分為一個(gè)較大的"Eden空間"和兩個(gè)較小的"Survivor空間"(通常稱為"S0"和"S1")。
新對(duì)象首先在Eden空間分配,當(dāng)Eden空間滿時(shí),觸發(fā)垃圾回收,將Eden空間和一個(gè)Survivor空間中的存活對(duì)象復(fù)制到另一個(gè)Survivor空間,然后清空Eden空間和已使用的Survivor空間。
這種方式更加高效,因?yàn)榇蠖鄶?shù)新生代對(duì)象的生命周期很短,不需要為它們預(yù)留太多的復(fù)制空間。
3.3.2 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 內(nèi)存分配簡單高效,只需要維護(hù)一個(gè)指針,按順序分配內(nèi)存。
- 不會(huì)產(chǎn)生內(nèi)存碎片,因?yàn)榇婊顚?duì)象被復(fù)制到新空間時(shí)是連續(xù)排列的。
- 回收效率高,只需要復(fù)制存活對(duì)象,不需要遍歷整個(gè)堆。
缺點(diǎn):
- 需要兩倍的內(nèi)存空間,內(nèi)存利用率低。
- 如果存活對(duì)象較多,復(fù)制的開銷會(huì)很大。
- 需要更新所有指向被移動(dòng)對(duì)象的引用,增加了復(fù)雜性。
3.3.3 適用場景
復(fù)制算法特別適用于新生代對(duì)象的回收,因?yàn)樾律鷮?duì)象的特點(diǎn)是:大部分對(duì)象生命周期很短,每次垃圾回收時(shí)只有少量對(duì)象存活。在這種情況下,復(fù)制算法的效率很高,因?yàn)橹恍枰獜?fù)制少量存活對(duì)象,而不需要處理大量的垃圾對(duì)象。
在HotSpot VM中,新生代默認(rèn)使用復(fù)制算法,而老年代使用標(biāo)記整理或標(biāo)記清除算法,這種組合充分利用了各種算法的優(yōu)勢,提高了整體的垃圾回收效率。
3.4 分代回收算法
分代回收(Generational Collection)算法是基于"弱分代假說"的垃圾回收算法,它將堆內(nèi)存分為不同的代(Generation),根據(jù)對(duì)象的年齡(即存活時(shí)間)將它們放在不同的代中,并對(duì)不同的代采用不同的垃圾回收策略。
3.4.1 原理與實(shí)現(xiàn)
分代回收算法的基本思想是:大多數(shù)對(duì)象的生命周期很短,只有少數(shù)對(duì)象能夠長期存活?;谶@一觀察,分代回收算法將堆內(nèi)存分為新生代(Young Generation)和老年代(Old Generation):
- 新生代:存放新創(chuàng)建的對(duì)象。由于大多數(shù)對(duì)象的生命周期很短,新生代的垃圾回收(Minor GC)頻繁發(fā)生,通常采用復(fù)制算法。
- 老年代:存放長期存活的對(duì)象。老年代的垃圾回收(Major GC或Full GC)較少發(fā)生,通常采用標(biāo)記整理或標(biāo)記清除算法。
在HotSpot VM中,新生代又細(xì)分為Eden空間和兩個(gè)Survivor空間(S0和S1)。新對(duì)象首先在Eden空間分配,當(dāng)Eden空間滿時(shí),觸發(fā)Minor GC,將Eden空間和一個(gè)Survivor空間中的存活對(duì)象復(fù)制到另一個(gè)Survivor空間,然后清空Eden空間和已使用的Survivor空間。經(jīng)過多次Minor GC仍然存活的對(duì)象,會(huì)被晉升到老年代。
3.4.2 分代假設(shè)
分代回收算法基于以下兩個(gè)假設(shè):
- 弱分代假說:大多數(shù)對(duì)象的生命周期很短。
- 強(qiáng)分代假說:經(jīng)過多次垃圾回收仍然存活的對(duì)象,很可能會(huì)繼續(xù)存活很長時(shí)間。
這些假設(shè)在大多數(shù)Java應(yīng)用程序中都成立,因此分代回收算法通常能夠取得良好的效果。然而,對(duì)于某些特殊的應(yīng)用場景(如大量長壽命對(duì)象的創(chuàng)建和銷毀),這些假設(shè)可能不成立,分代回收算法的效果可能不如預(yù)期。
3.4.3 新生代與老年代
新生代和老年代的主要區(qū)別在于對(duì)象的生命周期和垃圾回收策略:
新生代:
- 存放新創(chuàng)建的對(duì)象。
- 空間較小,通常只占整個(gè)堆的1/3或更少。
- 垃圾回收頻繁,采用復(fù)制算法。
- 每次垃圾回收會(huì)清理大量對(duì)象,效率較高。
老年代:
- 存放長期存活的對(duì)象和大對(duì)象。
- 空間較大,通常占整個(gè)堆的2/3或更多。
- 垃圾回收較少,采用標(biāo)記整理或標(biāo)記清除算法。
- 每次垃圾回收的開銷較大,可能導(dǎo)致較長的暫停時(shí)間。
對(duì)象從新生代晉升到老年代的條件通常包括:
- 對(duì)象在新生代經(jīng)過一定次數(shù)的垃圾回收仍然存活。
- 對(duì)象太大,無法在新生代分配。
- Survivor空間不足以容納所有存活對(duì)象。
3.4.4 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 針對(duì)不同生命周期的對(duì)象采用不同的垃圾回收策略,提高了垃圾回收的效率。
- 減少了全堆掃描的次數(shù),降低了垃圾回收的開銷。
- 新生代的垃圾回收速度快,暫停時(shí)間短,提高了程序的響應(yīng)性。
缺點(diǎn):
- 實(shí)現(xiàn)復(fù)雜,需要維護(hù)多個(gè)內(nèi)存區(qū)域和對(duì)象的年齡信息。
- 對(duì)象晉升策略的選擇對(duì)性能有較大影響,需要根據(jù)應(yīng)用特性進(jìn)行調(diào)優(yōu)。
- 老年代的垃圾回收仍然可能導(dǎo)致較長的暫停時(shí)間。
3.5 增量式回收算法
增量式回收(Incremental Collection)算法是一種旨在減少垃圾回收暫停時(shí)間的算法,它將垃圾回收過程分解為多個(gè)小步驟,穿插在程序執(zhí)行過程中,從而避免長時(shí)間的暫停。
3.5.1 原理與實(shí)現(xiàn)
傳統(tǒng)的垃圾回收算法(如標(biāo)記清除、標(biāo)記整理)通常需要在垃圾回收過程中暫停程序執(zhí)行,這被稱為"Stop-The-World"(STW)暫停。對(duì)于大型堆,這種暫??赡艹掷m(xù)數(shù)秒甚至數(shù)分鐘,嚴(yán)重影響程序的響應(yīng)性。
增量式回收算法的基本思想是將垃圾回收過程分解為多個(gè)小步驟,每次只執(zhí)行一小部分工作,然后讓程序繼續(xù)執(zhí)行一段時(shí)間,再執(zhí)行下一個(gè)垃圾回收步驟。這樣,垃圾回收的暫停時(shí)間被分散到多個(gè)短暫的暫停中,減少了單次暫停的時(shí)間,提高了程序的響應(yīng)性。
3.5.2 三色標(biāo)記法
三色標(biāo)記法是實(shí)現(xiàn)增量式回收的一種常用技術(shù),它將對(duì)象分為三種顏色:
- 白色:未被標(biāo)記的對(duì)象,潛在的垃圾。
- 灰色:已被標(biāo)記但其引用尚未被掃描的對(duì)象。
- 黑色:已被標(biāo)記且其所有引用都已被掃描的對(duì)象。
垃圾回收過程從根對(duì)象開始,初始時(shí)所有對(duì)象都是白色,根對(duì)象被標(biāo)記為灰色。然后,垃圾回收器重復(fù)以下步驟:
- 從灰色對(duì)象集合中取出一個(gè)對(duì)象。
- 將該對(duì)象標(biāo)記為黑色。
- 將該對(duì)象引用的所有白色對(duì)象標(biāo)記為灰色。
- 如果灰色對(duì)象集合為空,則垃圾回收結(jié)束;否則,返回步驟1。
在增量式回收中,垃圾回收器可以在執(zhí)行一定數(shù)量的上述步驟后暫停,讓程序繼續(xù)執(zhí)行,然后再繼續(xù)執(zhí)行垃圾回收步驟。
然而,這種方式存在一個(gè)問題:在垃圾回收暫停期間,程序可能修改對(duì)象引用關(guān)系,導(dǎo)致某些本應(yīng)被標(biāo)記的對(duì)象被錯(cuò)誤地回收。
為了解決這個(gè)問題,增量式回收通常需要使用寫屏障(Write Barrier)技術(shù),監(jiān)控程序?qū)?duì)象引用的修改,確保垃圾回收的正確性。
3.5.3 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 減少了單次垃圾回收的暫停時(shí)間,提高了程序的響應(yīng)性。
- 適用于對(duì)實(shí)時(shí)性要求較高的應(yīng)用,如游戲、多媒體應(yīng)用等。
- 可以與其他垃圾回收算法(如分代回收)結(jié)合使用,進(jìn)一步提高效率。
缺點(diǎn):
- 實(shí)現(xiàn)復(fù)雜,需要使用寫屏障等技術(shù)確保垃圾回收的正確性。
- 總體垃圾回收時(shí)間可能增加,因?yàn)樾枰~外的工作來維護(hù)垃圾回收狀態(tài)。
- 內(nèi)存占用可能增加,因?yàn)樾枰鎯?chǔ)對(duì)象的顏色信息。
3.6 并發(fā)回收算法
并發(fā)回收(Concurrent Collection)算法是一種允許垃圾回收與程序并發(fā)執(zhí)行的算法,旨在進(jìn)一步減少垃圾回收對(duì)程序執(zhí)行的影響。
3.6.1 原理與實(shí)現(xiàn)
并發(fā)回收算法的基本思想是讓垃圾回收線程與應(yīng)用程序線程并發(fā)執(zhí)行,而不是暫停應(yīng)用程序線程。這樣,垃圾回收的大部分工作可以在應(yīng)用程序繼續(xù)執(zhí)行的同時(shí)完成,只有少量必要的操作(如初始標(biāo)記和最終標(biāo)記)需要暫停應(yīng)用程序。
并發(fā)回收算法通?;谌珮?biāo)記法,但需要更復(fù)雜的機(jī)制來處理并發(fā)執(zhí)行帶來的問題。例如,在垃圾回收過程中,應(yīng)用程序可能修改對(duì)象引用關(guān)系,導(dǎo)致某些本應(yīng)被標(biāo)記的對(duì)象被錯(cuò)誤地回收。為了解決這個(gè)問題,并發(fā)回收算法通常使用寫屏障和讀屏障技術(shù),監(jiān)控應(yīng)用程序?qū)?duì)象引用的修改和訪問,確保垃圾回收的正確性。
3.6.2 與增量式回收的區(qū)別
并發(fā)回收和增量式回收都旨在減少垃圾回收的暫停時(shí)間,但它們的實(shí)現(xiàn)方式不同:
- 增量式回收:將垃圾回收過程分解為多個(gè)小步驟,每次只執(zhí)行一小部分工作,然后讓程序繼續(xù)執(zhí)行一段時(shí)間,再執(zhí)行下一個(gè)垃圾回收步驟。垃圾回收和程序執(zhí)行是交替進(jìn)行的。
- 并發(fā)回收:讓垃圾回收線程與應(yīng)用程序線程并發(fā)執(zhí)行,垃圾回收和程序執(zhí)行是同時(shí)進(jìn)行的。
并發(fā)回收通常能夠提供更短的暫停時(shí)間,但實(shí)現(xiàn)更加復(fù)雜,對(duì)系統(tǒng)資源的要求也更高。
3.6.3 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 大幅減少了垃圾回收的暫停時(shí)間,提高了程序的響應(yīng)性。
- 適用于對(duì)實(shí)時(shí)性要求極高的應(yīng)用,如金融交易系統(tǒng)、在線游戲服務(wù)器等。
- 可以充分利用多核處理器的計(jì)算能力。
缺點(diǎn):
- 實(shí)現(xiàn)非常復(fù)雜,需要使用寫屏障、讀屏障等技術(shù)確保垃圾回收的正確性。
- 總體垃圾回收時(shí)間可能增加,因?yàn)椴l(fā)執(zhí)行帶來了額外的同步開銷。
- 對(duì)系統(tǒng)資源(如CPU、內(nèi)存)的要求較高。
- 在某些情況下,可能無法及時(shí)回收垃圾,導(dǎo)致內(nèi)存占用增加。
四、Java的GC觸發(fā)條件
Java的垃圾回收機(jī)制是其核心特性之一,它使用分代回收算法,將堆內(nèi)存分為新生代、老年代和永久代(在JDK 8中被元空間取代)。Java的GC觸發(fā)條件主要包括Minor GC和Full GC兩種。
4.1 Minor GC觸發(fā)條件
Minor GC(新生代GC)主要回收新生代的對(duì)象,觸發(fā)條件相對(duì)簡單:
- Eden空間不足:當(dāng)Eden空間無法滿足新對(duì)象的分配需求時(shí),會(huì)觸發(fā)Minor GC。這是最常見的觸發(fā)條件。
Minor GC的過程是:
- 標(biāo)記Eden空間和一個(gè)Survivor空間(From空間)中的所有存活對(duì)象。
- 將這些存活對(duì)象復(fù)制到另一個(gè)Survivor空間(To空間)。
- 清空Eden空間和From空間。
- 交換From空間和To空間的角色。
由于新生代對(duì)象的生命周期通常很短,大部分對(duì)象在Minor GC后就會(huì)被回收,因此Minor GC的效率通常很高,暫停時(shí)間也較短。
4.2 Full GC觸發(fā)條件
Full GC(完全GC)會(huì)回收整個(gè)堆內(nèi)存,包括新生代、老年代和元空間(或永久代)。Full GC的觸發(fā)條件更加復(fù)雜,主要包括:
- 老年代空間不足:當(dāng)老年代空間無法滿足對(duì)象晉升或大對(duì)象直接分配的需求時(shí),會(huì)觸發(fā)Full GC。
- 元空間(或永久代)空間不足:當(dāng)元空間(或永久代)無法滿足類加載的需求時(shí),會(huì)觸發(fā)Full GC。
- 顯式調(diào)用System.gc():雖然這只是一個(gè)建議,但大多數(shù)JVM實(shí)現(xiàn)會(huì)在調(diào)用System.gc()時(shí)執(zhí)行Full GC。
- 老年代的擔(dān)保失敗:在進(jìn)行Minor GC前,JVM會(huì)檢查老年代最大可用連續(xù)空間是否大于新生代所有對(duì)象的總大小。如果條件成立,則Minor GC是安全的;否則,JVM會(huì)查看是否允許擔(dān)保失?。℉andlePromotionFailure)。如果允許,JVM會(huì)繼續(xù)檢查老年代最大可用連續(xù)空間是否大于歷次晉升到老年代的對(duì)象的平均大小,如果大于,則嘗試進(jìn)行Minor GC(但風(fēng)險(xiǎn)較大);如果小于,或者不允許擔(dān)保失敗,則改為進(jìn)行Full GC。
- CMS GC的并發(fā)失敗:使用CMS(Concurrent Mark Sweep)收集器時(shí),如果并發(fā)收集過程中出現(xiàn)"并發(fā)模式失敗"(Concurrent Mode Failure)或"晉升失敗"(Promotion Failed),會(huì)觸發(fā)Full GC。
Full GC的過程通常包括標(biāo)記、清除和整理三個(gè)階段,由于需要處理整個(gè)堆內(nèi)存,因此Full GC的暫停時(shí)間通常較長,對(duì)程序的響應(yīng)性有較大影響。
4.3 各種GC收集器的觸發(fā)差異
Java提供了多種GC收集器,每種收集器的觸發(fā)條件和行為可能有所不同:
Serial收集器:單線程收集器,觸發(fā)條件與上述相同。
ParNew收集器:Serial收集器的多線程版本,觸發(fā)條件與上述相同。
Parallel Scavenge收集器:關(guān)注吞吐量的多線程收集器,可以通過參數(shù)控制GC觸發(fā)的頻率和時(shí)間。
CMS收集器:關(guān)注暫停時(shí)間的并發(fā)收集器,除了上述觸發(fā)條件外,還有以下特殊條件:
- 當(dāng)老年代使用率達(dá)到某個(gè)閾值(默認(rèn)為92%)時(shí),會(huì)觸發(fā)并發(fā)收集。
- 如果在并發(fā)收集過程中,老年代空間不足,會(huì)觸發(fā)"并發(fā)模式失敗",導(dǎo)致Full GC。
G1收集器:面向服務(wù)端應(yīng)用的收集器,采用區(qū)域化分代的思想,觸發(fā)條件更加復(fù)雜:
- 當(dāng)Eden區(qū)域用盡時(shí),會(huì)觸發(fā)年輕代收集。
- 當(dāng)整個(gè)堆的使用率達(dá)到某個(gè)閾值,或者預(yù)測的GC停頓時(shí)間超過目標(biāo)停頓時(shí)間時(shí),會(huì)觸發(fā)混合收集(Mixed GC)。
- 如果在收集過程中,堆空間不足,會(huì)觸發(fā)Full GC。
ZGC和Shenandoah收集器:這兩種收集器都是低延遲收集器,旨在將GC暫停時(shí)間控制在10ms以內(nèi)。它們的觸發(fā)條件主要基于堆使用率和預(yù)測的GC停頓時(shí)間。
五、Java垃圾回收的實(shí)際應(yīng)用與優(yōu)化
理解Java垃圾回收的原理和觸發(fā)條件后,我們可以更好地優(yōu)化應(yīng)用程序的內(nèi)存使用,避免常見的內(nèi)存問題,提高程序的性能和穩(wěn)定性。
5.1 常見內(nèi)存問題及解決方案
5.1.1 內(nèi)存泄漏
內(nèi)存泄漏是指程序分配的內(nèi)存無法被垃圾回收器回收,導(dǎo)致內(nèi)存使用量不斷增加,最終可能導(dǎo)致程序崩潰。在Java中,常見的內(nèi)存泄漏原因和解決方案包括:
靜態(tài)集合類:
- 原因:靜態(tài)集合類的生命周期與應(yīng)用程序相同,如果不斷向其中添加對(duì)象而不移除,會(huì)導(dǎo)致內(nèi)存泄漏。
- 解決方案:及時(shí)清理不再使用的對(duì)象,使用緩存策略限制集合大小。
未關(guān)閉的資源:
- 原因:未關(guān)閉的文件、數(shù)據(jù)庫連接、網(wǎng)絡(luò)連接等資源會(huì)占用內(nèi)存。
- 解決方案:使用try-with-resources語句或finally塊確保資源被正確關(guān)閉。
內(nèi)部類和匿名內(nèi)部類:
- 原因:內(nèi)部類和匿名內(nèi)部類持有外部類的引用,可能導(dǎo)致外部類無法被回收。
- 解決方案:使用靜態(tài)內(nèi)部類,避免不必要的外部類引用。
ThreadLocal變量:
- 原因:ThreadLocal變量在線程結(jié)束后沒有被移除,可能導(dǎo)致內(nèi)存泄漏。
- 解決方案:在不再需要ThreadLocal變量時(shí)調(diào)用remove()方法。
監(jiān)聽器和回調(diào):
- 原因:注冊(cè)監(jiān)聽器或回調(diào)后未取消注冊(cè),導(dǎo)致對(duì)象無法被回收。
- 解決方案:在不再需要時(shí)顯式取消注冊(cè),或使用弱引用存儲(chǔ)回調(diào)函數(shù)。
5.1.2 內(nèi)存碎片
內(nèi)存碎片是指內(nèi)存空間被分割成多個(gè)小塊,雖然總的空閑內(nèi)存足夠,但無法滿足大對(duì)象的分配需求。在Java中,內(nèi)存碎片主要出現(xiàn)在使用標(biāo)記清除算法的老年代中。解決方案包括:
- 使用標(biāo)記整理算法:標(biāo)記整理算法會(huì)將存活對(duì)象移動(dòng)到堆的一端,消除內(nèi)存碎片。
- 調(diào)整垃圾回收器:選擇適合應(yīng)用特性的垃圾回收器,如G1收集器可以減少內(nèi)存碎片。
- 增加堆大小:增加堆大小可以減輕內(nèi)存碎片的影響,但會(huì)增加垃圾回收的開銷。
5.1.3 過早提升
過早提升是指本應(yīng)在新生代被回收的短生命周期對(duì)象被提前晉升到老年代,導(dǎo)致老年代垃圾回收頻率增加,影響程序性能。解決方案包括:
- 增加新生代大小:增加新生代大小可以減少M(fèi)inor GC的頻率,降低對(duì)象被提前晉升的可能性。
- 調(diào)整對(duì)象晉升閾值:增加對(duì)象晉升到老年代的年齡閾值,使對(duì)象在新生代停留更長時(shí)間。
- 避免大對(duì)象:避免創(chuàng)建短生命周期的大對(duì)象,因?yàn)榇髮?duì)象通常直接分配在老年代。
5.2 JVM GC調(diào)優(yōu)最佳實(shí)踐
5.2.1 JVM GC調(diào)優(yōu)參數(shù)
JVM提供了豐富的參數(shù)來調(diào)優(yōu)垃圾回收行為,以下是一些常用的參數(shù):
堆大小相關(guān):
-Xms
:初始堆大小-Xmx
:最大堆大小-Xmn
:新生代大小-XX:SurvivorRatio
:Eden區(qū)與Survivor區(qū)的比例
垃圾回收器選擇:
-XX:+UseSerialGC
:使用Serial垃圾回收器-XX:+UseParallelGC
:使用Parallel垃圾回收器-XX:+UseConcMarkSweepGC
:使用CMS垃圾回收器-XX:+UseG1GC
:使用G1垃圾回收器-XX:+UseZGC
:使用ZGC垃圾回收器(JDK 11+)-XX:+UseShenandoahGC
:使用Shenandoah垃圾回收器(JDK 12+)
垃圾回收行為控制:
-XX:MaxGCPauseMillis
:最大垃圾回收停頓時(shí)間-XX:GCTimeRatio
:垃圾回收時(shí)間占總時(shí)間的比例-XX:+DisableExplicitGC
:禁用顯式垃圾回收(System.gc())
內(nèi)存分配相關(guān):
-XX:PretenureSizeThreshold
:大對(duì)象直接進(jìn)入老年代的閾值-XX:MaxTenuringThreshold
:對(duì)象晉升到老年代的年齡閾值-XX:+AlwaysPreTouch
:在JVM啟動(dòng)時(shí)就觸及所有內(nèi)存頁面,避免運(yùn)行時(shí)的延遲
調(diào)優(yōu)JVM垃圾回收的一般步驟是:
- 監(jiān)控和分析當(dāng)前垃圾回收行為,識(shí)別問題。
- 根據(jù)應(yīng)用特性選擇合適的垃圾回收器。
- 調(diào)整堆大小和分代比例。
- 調(diào)整垃圾回收參數(shù),平衡暫停時(shí)間和吞吐量。
- 測試和驗(yàn)證調(diào)優(yōu)效果,必要時(shí)進(jìn)行進(jìn)一步調(diào)整。
5.2.2 對(duì)象池化技術(shù)
對(duì)象池是一種重用對(duì)象的技術(shù),可以減少對(duì)象創(chuàng)建和垃圾回收的開銷。對(duì)象池的基本思想是:預(yù)先創(chuàng)建一定數(shù)量的對(duì)象,當(dāng)需要使用對(duì)象時(shí)從池中獲取,使用完畢后歸還到池中,而不是創(chuàng)建新對(duì)象和銷毀舊對(duì)象。
在Java中,常見的對(duì)象池實(shí)現(xiàn)包括:
- Apache Commons Pool:提供通用的對(duì)象池實(shí)現(xiàn),支持多種池化策略。
- 數(shù)據(jù)庫連接池:如HikariCP、Druid、C3P0等,用于管理數(shù)據(jù)庫連接。
- 線程池:如ThreadPoolExecutor,用于管理線程資源。
- 字符串常量池:Java內(nèi)置的字符串常量池,用于重用字符串對(duì)象。
實(shí)現(xiàn)對(duì)象池的注意事項(xiàng):
- 池大小控制:池太小會(huì)導(dǎo)致頻繁創(chuàng)建新對(duì)象,池太大會(huì)占用過多內(nèi)存。
- 對(duì)象重置:從池中獲取對(duì)象后,需要將對(duì)象重置為初始狀態(tài)。
- 線程安全:在多線程環(huán)境中,對(duì)象池的操作需要保證線程安全。
- 過期策略:長時(shí)間未使用的對(duì)象可能需要從池中移除,以釋放內(nèi)存。
5.2.3 減少臨時(shí)對(duì)象創(chuàng)建
減少臨時(shí)對(duì)象的創(chuàng)建可以降低垃圾回收的頻率和開銷,提高程序性能。在Java中,以下是一些減少臨時(shí)對(duì)象創(chuàng)建的技巧:
字符串操作:
- 使用StringBuilder或StringBuffer進(jìn)行字符串拼接,而不是+運(yùn)算符。
- 使用String.intern()方法重用字符串常量。
集合操作:
- 預(yù)分配集合容量,避免動(dòng)態(tài)擴(kuò)容。
- 使用不可變集合,避免創(chuàng)建防御性副本。
- 使用Stream API處理集合,減少中間集合的創(chuàng)建。
基本類型與包裝類型:
- 優(yōu)先使用基本類型而不是包裝類型,避免自動(dòng)裝箱和拆箱。
- 使用基本類型數(shù)組而不是對(duì)象數(shù)組。
緩存計(jì)算結(jié)果:
- 對(duì)于計(jì)算開銷大但結(jié)果可重用的操作,使用緩存存儲(chǔ)計(jì)算結(jié)果。
- 使用懶加載和記憶化技術(shù),只在需要時(shí)計(jì)算并緩存結(jié)果。
對(duì)象復(fù)用:
- 使用對(duì)象池重用對(duì)象。
- 實(shí)現(xiàn)可重置的對(duì)象,在使用完畢后重置狀態(tài)而不是創(chuàng)建新對(duì)象。
5.3 未來發(fā)展趨勢
5.3.1 ZGC與Shenandoah
ZGC(Z Garbage Collector)和Shenandoah是兩種新一代的低延遲垃圾回收器,旨在將垃圾回收的暫停時(shí)間控制在毫秒級(jí)別,甚至亞毫秒級(jí)別。
ZGC:
- 由Oracle開發(fā),在JDK 11中引入,在JDK 15中成為生產(chǎn)就緒狀態(tài)。
- 使用基于區(qū)域的內(nèi)存布局,支持TB級(jí)別的堆大小。
- 采用并發(fā)標(biāo)記、并發(fā)整理和并發(fā)引用處理,大大減少了STW(Stop-The-World)暫停時(shí)間。
- 使用讀屏障(Load Barrier)技術(shù),確保并發(fā)執(zhí)行的正確性。
- 目標(biāo)是將垃圾回收暫停時(shí)間控制在10ms以內(nèi),不受堆大小影響。
Shenandoah:
- 由Red Hat開發(fā),在JDK 12中引入,在JDK 15中成為生產(chǎn)就緒狀態(tài)。
- 也是一種低延遲垃圾回收器,目標(biāo)是減少垃圾回收暫停時(shí)間。
- 使用Brooks指針(Brooks Pointers)技術(shù),允許對(duì)象在垃圾回收過程中并發(fā)移動(dòng)。
- 支持增量垃圾回收,可以根據(jù)應(yīng)用負(fù)載動(dòng)態(tài)調(diào)整垃圾回收的步調(diào)。
這兩種垃圾回收器代表了Java垃圾回收技術(shù)的最新發(fā)展方向,未來可能會(huì)進(jìn)一步優(yōu)化和普及,為大內(nèi)存、低延遲的Java應(yīng)用提供更好的支持。
5.3.2 機(jī)器學(xué)習(xí)輔助的GC
機(jī)器學(xué)習(xí)技術(shù)正在逐漸應(yīng)用于垃圾回收領(lǐng)域,通過分析應(yīng)用程序的內(nèi)存使用模式,預(yù)測垃圾回收的最佳時(shí)機(jī)和策略,提高垃圾回收的效率和準(zhǔn)確性。
機(jī)器學(xué)習(xí)輔助的垃圾回收可能包括以下方面:
- 預(yù)測對(duì)象生命周期:通過分析對(duì)象的創(chuàng)建和使用模式,預(yù)測對(duì)象的生命周期,優(yōu)化對(duì)象的分配和回收策略。
- 自適應(yīng)垃圾回收:根據(jù)應(yīng)用程序的運(yùn)行狀態(tài)和內(nèi)存使用模式,動(dòng)態(tài)調(diào)整垃圾回收的頻率、算法和參數(shù)。
- 內(nèi)存泄漏檢測:使用異常檢測算法識(shí)別潛在的內(nèi)存泄漏,提前預(yù)警和處理。
- 資源分配優(yōu)化:根據(jù)應(yīng)用程序的需求和系統(tǒng)資源狀態(tài),優(yōu)化內(nèi)存和CPU資源的分配,平衡垃圾回收和應(yīng)用程序執(zhí)行。
雖然機(jī)器學(xué)習(xí)輔助的垃圾回收還處于研究階段,但隨著機(jī)器學(xué)習(xí)技術(shù)的發(fā)展和垃圾回收需求的增長,這一領(lǐng)域有望取得重要突破。
5.3.3 硬件輔助的GC
硬件技術(shù)的發(fā)展也為Java垃圾回收提供了新的可能性,通過硬件支持提高垃圾回收的效率和性能。
硬件輔助的垃圾回收可能包括以下方面:
- 專用硬件加速器:設(shè)計(jì)專用的硬件加速器,加速垃圾回收的關(guān)鍵操作,如對(duì)象標(biāo)記、引用計(jì)數(shù)更新等。
- 內(nèi)存管理單元(MMU)支持:增強(qiáng)MMU的功能,支持垃圾回收相關(guān)的操作,如寫屏障、讀屏障等。
- 非易失性內(nèi)存(NVM):利用新型非易失性內(nèi)存技術(shù),如Intel的Optane,改變內(nèi)存層次結(jié)構(gòu),為垃圾回收提供新的可能性。
- 多核處理器優(yōu)化:針對(duì)多核處理器架構(gòu)優(yōu)化垃圾回收算法,提高并行和并發(fā)垃圾回收的效率。
硬件輔助的垃圾回收需要硬件和軟件的協(xié)同設(shè)計(jì),雖然實(shí)現(xiàn)難度較大,但有望在特定應(yīng)用場景中取得顯著的性能提升。
六、總結(jié)與展望
6.1 Java垃圾回收技術(shù)的發(fā)展歷程回顧
Java垃圾回收技術(shù)從最初的簡單標(biāo)記清除算法,發(fā)展到如今的復(fù)雜分代回收、并發(fā)回收和低延遲回收,經(jīng)歷了幾十年的演進(jìn)。這一發(fā)展歷程反映了Java平臺(tái)對(duì)內(nèi)存管理問題的不斷深入理解和優(yōu)化。
早期的Java垃圾回收器(如Serial收集器)簡單直觀但效率有限,隨著Java應(yīng)用需求的增長,垃圾回收技術(shù)也不斷創(chuàng)新,引入了并行回收(Parallel收集器)、并發(fā)回收(CMS收集器)和區(qū)域化分代回收(G1收集器)等高級(jí)技術(shù),大大提高了垃圾回收的效率和程序的響應(yīng)性。
近年來,隨著大數(shù)據(jù)、云計(jì)算和實(shí)時(shí)系統(tǒng)的興起,對(duì)Java垃圾回收的要求更加嚴(yán)格,促使了ZGC、Shenandoah等低延遲垃圾回收器的出現(xiàn),這些新一代垃圾回收器能夠在TB級(jí)別的堆上將垃圾回收暫停時(shí)間控制在毫秒級(jí)別,為大內(nèi)存、低延遲的Java應(yīng)用提供了有力支持。
6.2 各算法的適用場景對(duì)比
不同的Java垃圾收集器有各自的優(yōu)缺點(diǎn)和適用場景:
Serial收集器:
- 適用場景:單CPU環(huán)境、客戶端應(yīng)用、內(nèi)存受限的環(huán)境。
- 優(yōu)勢:簡單高效,內(nèi)存占用小。
- 劣勢:單線程收集,暫停時(shí)間長。
ParNew收集器:
- 適用場景:多CPU環(huán)境、需要與CMS配合的應(yīng)用。
- 優(yōu)勢:多線程收集,暫停時(shí)間短于Serial。
- 劣勢:仍然需要暫停應(yīng)用線程。
Parallel Scavenge收集器:
- 適用場景:注重吞吐量的后臺(tái)應(yīng)用、批處理系統(tǒng)。
- 優(yōu)勢:高吞吐量,可控制最大暫停時(shí)間。
- 劣勢:暫停時(shí)間可能較長。
CMS收集器:
- 適用場景:注重響應(yīng)時(shí)間的交互式應(yīng)用、Web應(yīng)用。
- 優(yōu)勢:并發(fā)收集,暫停時(shí)間短。
- 劣勢:CPU占用高,內(nèi)存碎片,并發(fā)失敗風(fēng)險(xiǎn)。
G1收集器:
- 適用場景:大內(nèi)存、需要平衡吞吐量和暫停時(shí)間的應(yīng)用。
- 優(yōu)勢:可預(yù)測的暫停時(shí)間,區(qū)域化分代,減少內(nèi)存碎片。
- 劣勢:復(fù)雜度高,在某些場景下吞吐量不如Parallel。
ZGC和Shenandoah收集器:
- 適用場景:對(duì)暫停時(shí)間要求極高的實(shí)時(shí)應(yīng)用、大內(nèi)存應(yīng)用。
- 優(yōu)勢:極低的暫停時(shí)間,支持TB級(jí)別堆。
- 劣勢:吞吐量可能降低,實(shí)現(xiàn)復(fù)雜,對(duì)硬件要求高。
在實(shí)際應(yīng)用中,應(yīng)根據(jù)應(yīng)用特性和需求選擇合適的垃圾回收器,并進(jìn)行適當(dāng)?shù)恼{(diào)優(yōu)。例如,對(duì)于注重吞吐量的批處理系統(tǒng),可以選擇Parallel收集器;對(duì)于注重響應(yīng)時(shí)間的Web應(yīng)用,可以選擇CMS或G1收集器;對(duì)于對(duì)暫停時(shí)間要求極高的實(shí)時(shí)應(yīng)用,可以選擇ZGC或Shenandoah收集器。
6.3 Java垃圾回收技術(shù)的未來發(fā)展方向
Java垃圾回收技術(shù)的未來發(fā)展方向主要包括以下幾個(gè)方面:
- 低延遲垃圾回收:隨著實(shí)時(shí)系統(tǒng)和交互式應(yīng)用的普及,對(duì)垃圾回收暫停時(shí)間的要求越來越嚴(yán)格。未來的Java垃圾回收器將更加注重減少暫停時(shí)間,甚至實(shí)現(xiàn)無暫停的垃圾回收。
- 大內(nèi)存支持:隨著內(nèi)存容量的增長和大數(shù)據(jù)應(yīng)用的興起,Java垃圾回收器需要能夠高效地管理TB級(jí)別甚至更大的堆內(nèi)存。
- 智能化垃圾回收:利用機(jī)器學(xué)習(xí)和人工智能技術(shù),分析應(yīng)用程序的內(nèi)存使用模式,預(yù)測垃圾回收的最佳時(shí)機(jī)和策略,實(shí)現(xiàn)自適應(yīng)的垃圾回收。
- 硬件協(xié)同優(yōu)化:與硬件廠商合作,設(shè)計(jì)專用的硬件加速器或增強(qiáng)現(xiàn)有硬件的功能,提高垃圾回收的效率和性能。
- 特定領(lǐng)域優(yōu)化:針對(duì)特定應(yīng)用領(lǐng)域(如大數(shù)據(jù)、云計(jì)算、邊緣計(jì)算等)的需求,開發(fā)專門的垃圾回收策略和算法。
- 編程模型和運(yùn)行時(shí)的協(xié)同設(shè)計(jì):將垃圾回收考慮納入編程模型和運(yùn)行時(shí)的設(shè)計(jì)中,通過語言特性和編譯優(yōu)化減輕垃圾回收的負(fù)擔(dān)。
Java垃圾回收技術(shù)的發(fā)展將繼續(xù)推動(dòng)Java平臺(tái)的進(jìn)步,為開發(fā)人員提供更高效、更可靠的內(nèi)存管理機(jī)制,使他們能夠更加專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),而不必過多關(guān)注內(nèi)存管理的細(xì)節(jié)。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring boot+thymeleaf+bootstrap實(shí)現(xiàn)后臺(tái)管理系統(tǒng)界面
這篇文章主要為大家詳細(xì)介紹了spring boot+thymeleaf+bootstrap簡單實(shí)現(xiàn)后臺(tái)管理系統(tǒng)界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12淺析SpringBoot自動(dòng)化配置原理實(shí)現(xiàn)
這篇文章主要介紹了淺析SpringBoot自動(dòng)化配置原理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06如何使用Spring boot的@Transactional進(jìn)行事務(wù)管理
這篇文章介紹了SpringBoot中使用@Transactional注解進(jìn)行聲明式事務(wù)管理的詳細(xì)信息,包括基本用法、核心配置參數(shù)、關(guān)鍵注意事項(xiàng)、調(diào)試技巧、最佳實(shí)踐以及完整示例,感興趣的朋友一起看看吧2025-02-02sentinel?整合spring?cloud限流的過程解析
這篇文章主要介紹了sentinel?整合spring?cloud限流,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03