1. 程式人生 > >一文讀懂Java GC原理和調優

一文讀懂Java GC原理和調優

概述

本文介紹GC基礎原理和理論,GC調優方法思路和方法,基於Hotspot jdk1.8,學習之後將瞭解如何對生產系統出現的GC問題進行排查解決

閱讀時長約30分鐘,內容主要如下:

  • GC基礎原理,涉及調優目標,GC事件分類、JVM記憶體分配策略、GC日誌分析等
  • CMS原理及調優
  • G1原理及調優
  • GC問題排查和解決思路

GC基礎原理

1 GC調優目標

大多數情況下對 Java 程式進行GC調優, 主要關注兩個目標:響應速度、吞吐量

  • 響應速度(Responsiveness) 響應速度指程式或系統對一個請求的響應有多迅速。比如,使用者訂單查詢響應時間,對響應速度要求很高的系統,較大的停頓時間是不可接受的。調優的重點是在短的時間內快速響應

  • 吞吐量(Throughput) 吞吐量關注在一個特定時間段內應用系統的最大工作量,例如每小時批處理系統能完成的任務數量,在吞吐量方面優化的系統,較長的GC停頓時間也是可以接受的,因為高吞吐量應用更關心的是如何儘可能快地完成整個任務,不考慮快速響應使用者請求

GC調優中,GC導致的應用暫停時間影響系統響應速度,GC處理執行緒的CPU使用率影響系統吞吐量

2 GC分代收集演算法

現代的垃圾收集器基本都是採用分代收集演算法,其主要思想: 將Java的堆記憶體邏輯上分成兩塊:新生代、老年代,針對不同存活週期、不同大小的物件採取不同的垃圾回收策略

分代收集演算法

  • 新生代(Young Generation)

新生代又叫年輕代,大多數物件在新生代中被建立,很多物件的生命週期很短。每次新生代的垃圾回收(又稱Young GC、Minor GC、YGC)後只有少量物件存活,所以使用複製演算法,只需少量的複製操作成本就可以完成回收

新生代內又分三個區:一個Eden區,兩個Survivor區(S0、S1,又稱From Survivor、To Survivor),大部分物件在Eden區中生成。當Eden區滿時,還存活的物件將被複制到兩個Survivor區(中的一個)。當這個Survivor區滿時,此區的存活且不滿足晉升到老年代條件的物件將被複制到另外一個Survivor區。物件每經歷一次複製,年齡加1,達到晉升年齡閾值後,轉移到老年代

  • 老年代(Old Generation)

在新生代中經歷了N次垃圾回收後仍然存活的物件,就會被放到老年代,該區域中物件存活率高。老年代的垃圾回收通常使用“標記-整理”演算法

3 GC事件分類

根據垃圾收集回收的區域不同,垃圾收集主要通常分為Young GC、Old GC、Full GC、Mixed GC

(1) Young GC

新生代記憶體的垃圾收集事件稱為Young GC(又稱Minor GC),當JVM無法為新物件分配在新生代記憶體空間時總會觸發 Young GC,比如 Eden 區佔滿時。新物件分配頻率越高, Young GC 的頻率就越高

Young GC 每次都會引起全線停頓(Stop-The-World),暫停所有的應用執行緒,停頓時間相對老年代GC的造成的停頓,幾乎可以忽略不計

(2) Old GC 、Full GC、Mixed GC

Old GC,只清理老年代空間的GC事件,只有CMS的併發收集是這個模式 Full GC,清理整個堆的GC事件,包括新生代、老年代、元空間等

  • Mixed GC,清理整個新生代以及部分老年代的GC,只有G1有這個模式

4 GC日誌分析

GC日誌是一個很重要的工具,它準確記錄了每一次的GC的執行時間和執行結果,通過分析GC日誌可以調優堆設定和GC設定,或者改進應用程式的物件分配模式,開啟的JVM啟動引數如下:

-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps  -XX:+PrintGCTimeStamps

常見的Young GC、Full GC日誌含義如下:

Young GC

Full GC

免費的GC日誌圖形分析工具推薦下面2個:

  • GCViewer,下載jar包直接執行
  • gceasy,web工具,上傳GC日誌線上使用

5 記憶體分配策略

Java提供的自動記憶體管理,可以歸結為解決了物件的記憶體分配和回收的問題,前面已經介紹了記憶體回收,下面介紹幾條最普遍的記憶體分配策略

  • 物件優先在Eden區分配 大多數情況下,物件在先新生代Eden區中分配。當Eden區沒有足夠空間進行分配時,虛擬機器將發起一次Young GC

  • 大物件之間進入老年代 JVM提供了一個物件大小閾值引數(-XX:PretenureSizeThreshold,預設值為0,代表不管多大都是先在Eden中分配記憶體),大於引數設定的閾值值的物件直接在老年代分配,這樣可以避免物件在Eden及兩個Survivor直接發生大記憶體複製

  • 長期存活的物件將進入老年代 物件每經歷一次垃圾回收,且沒被回收掉,它的年齡就增加1,大於年齡閾值引數(-XX:MaxTenuringThreshold,預設15)的物件,將晉升到老年代中

  • 空間分配擔保 當進行Young GC之前,JVM需要預估:老年代是否能夠容納Young GC後新生代晉升到老年代的存活物件,以確定是否需要提前觸發GC回收老年代空間,基於空間分配擔保策略來計算:

continueSize:老年代最大可用連續空間

空間分配擔保

Young GC之後如果成功(Young GC後晉升物件能放入老年代),則代表擔保成功,不用再進行Full GC,提高效能;如果失敗,則會出現“promotion failed”錯誤,代表擔保失敗,需要進行Full GC

  • 動態年齡判定 新生代物件的年齡可能沒達到閾值(MaxTenuringThreshold引數指定)就晉升老年代,如果Young GC之後,新生代存活物件達到相同年齡所有物件大小的總和大於任一Survivor空間(S0 或 S1總空間)的一半,此時S0或者S1區即將容納不了存活的新生代物件,年齡大於或等於該年齡的物件就可以直接進入老年代,無須等到MaxTenuringThreshold中要求的年齡

另外,如果Young GC後S0或S1區不足以容納:未達到晉升老年代條件的新生代存活物件,會導致這些存活物件直接進入老年代,需要儘量避免

CMS原理及調優

1 名詞解釋

可達性分析演算法:用於判斷物件是否存活,基本思想是通過一系列稱為“GC Root”的物件作為起點(常見的GC Root有系統類載入器、棧中的物件、處於啟用狀態的執行緒等),基於物件引用關係,從GC Roots開始向下搜尋,所走過的路徑稱為引用鏈,當一個物件到GC Root沒有任何引用鏈相連,證明物件不再存活

Stop The World:GC過程中分析物件引用關係,為了保證分析結果的準確性,需要通過停頓所有Java執行執行緒,保證引用關係不再動態變化,該停頓事件稱為Stop The World(STW)

Safepoint:程式碼執行過程中的一些特殊位置,當執行緒執行到這些位置的時候,說明虛擬機器當前的狀態是安全的,如果有需要GC,執行緒可以在這個位置暫停。HotSpot採用主動中斷的方式,讓執行執行緒在執行期輪詢是否需要暫停的標誌,若需要則中斷掛起

2 CMS簡介

CMS(Concurrent Mark and Swee 併發-標記-清除),是一款基於併發、使用標記清除演算法的垃圾回收演算法,只針對老年代進行垃圾回收。CMS收集器工作時,儘可能讓GC執行緒和使用者執行緒併發執行,以達到降低STW時間的目的

通過以下命令列引數,啟用CMS垃圾收集器:

-XX:+UseConcMarkSweepGC

值得補充的是,下面介紹到的CMS GC是指老年代的GC,而Full GC指的是整個堆的GC事件,包括新生代、老年代、元空間等,兩者有所區分

3 新生代垃圾回收

能與CMS搭配使用的新生代垃圾收集器有Serial收集器和ParNew收集器。這2個收集器都採用標記複製演算法,都會觸發STW事件,停止所有的應用執行緒。不同之處在於,Serial是單執行緒執行,ParNew是多執行緒執行

新生代

4 老年代垃圾回收

CMS GC以獲取最小停頓時間為目的,儘可能減少STW時間,可以分為7個階段

CMS 7個階段

  • 階段 1: 初始標記(Initial Mark)

此階段的目標是標記老年代中所有存活的物件, 包括 GC Root 的直接引用, 以及由新生代中存活物件所引用的物件,觸發第一次STW事件

這個過程是支援多執行緒的(JDK7之前單執行緒,JDK8之後並行,可通過引數CMSParallelInitialMarkEnabled調整)

初始標記

  • 階段 2: 併發標記(Concurrent Mark)

此階段GC執行緒和應用執行緒併發執行,遍歷階段1初始標記出來的存活物件,然後繼續遞迴標記這些物件可達的物件

併發標記

  • 階段 3: 併發預清理(Concurrent Preclean)

此階段GC執行緒和應用執行緒也是併發執行,因為階段2是與應用執行緒併發執行,可能有些引用關係已經發生改變。 通過卡片標記(Card Marking),提前把老年代空間邏輯劃分為相等大小的區域(Card),如果引用關係發生改變,JVM會將發生改變的區域標記位“髒區”(Dirty Card),然後在本階段,這些髒區會被找出來,重新整理引用關係,清除“髒區”標記

併發預清理

  • 階段 4: 併發可取消的預清理(Concurrent Abortable Preclean)

此階段也不停止應用執行緒. 本階段嘗試在 STW 的 最終標記階段(Final Remark)之前儘可能地多做一些工作,以減少應用暫停時間 在該階段不斷迴圈處理:標記老年代的可達物件、掃描處理Dirty Card區域中的物件,迴圈的終止條件有: 1 達到迴圈次數 2 達到迴圈執行時間閾值 3 新生代記憶體使用率達到閾值

  • 階段 5: 最終標記(Final Remark)

這是GC事件中第二次(也是最後一次)STW階段,目標是完成老年代中所有存活物件的標記。在此階段執行: 1 遍歷新生代物件,重新標記 2 根據GC Roots,重新標記 3 遍歷老年代的Dirty Card,重新標記

  • 階段 6: 併發清除(Concurrent Sweep)

此階段與應用程式併發執行,不需要STW停頓,根據標記結果清除垃圾物件

併發清除

  • 階段 7: 併發重置(Concurrent Reset)

此階段與應用程式併發執行,重置CMS演算法相關的內部資料, 為下一次GC迴圈做準備

5 CMS常見問題

最終標記階段停頓時間過長問題

CMS的GC停頓時間約80%都在最終標記階段(Final Remark),若該階段停頓時間過長,常見原因是新生代對老年代的無效引用,在上一階段的併發可取消預清理階段中,執行閾值時間內未完成迴圈,來不及觸發Young GC,清理這些無效引用

通過新增引數:-XX:+CMSScavengeBeforeRemark。在執行最終操作之前先觸發Young GC,從而減少新生代對老年代的無效引用,降低最終標記階段的停頓,但如果在上個階段(併發可取消的預清理)已觸發Young GC,也會重複觸發Young GC

併發模式失敗(concurrent mode failure) & 晉升失敗(promotion failed)問題

併發模式失敗

併發模式失敗:當CMS在執行回收時,新生代發生垃圾回收,同時老年代又沒有足夠的空間容納晉升的物件時,CMS 垃圾回收就會退化成單執行緒的Full GC。所有的應用執行緒都會被暫停,老年代中所有的無效物件都被回收

晉升失敗

晉升失敗:當新生代發生垃圾回收,老年代有足夠的空間可以容納晉升的物件,但是由於空閒空間的碎片化,導致晉升失敗,此時會觸發單執行緒且帶壓縮動作的Full GC

併發模式失敗和晉升失敗都會導致長時間的停頓,常見解決思路如下:

  • 降低觸發CMS GC的閾值,即引數-XX:CMSInitiatingOccupancyFraction的值,讓CMS GC儘早執行,以保證有足夠的空間
  • 增加CMS執行緒數,即引數-XX:ConcGCThreads,
  • 增大老年代空間
  • 讓物件儘量在新生代回收,避免進入老年代

記憶體碎片問題

通常CMS的GC過程基於標記清除演算法,不帶壓縮動作,導致越來越多的記憶體碎片需要壓縮,常見以下場景會觸發記憶體碎片壓縮:

  • 新生代Young GC出現新生代晉升擔保失敗(promotion failed)
  • 程式主動執行System.gc()

可通過引數CMSFullGCsBeforeCompaction的值,設定多少次Full GC觸發一次壓縮,預設值為0,代表每次進入Full GC都會觸發壓縮,帶壓縮動作的演算法為上面提到的單執行緒Serial Old演算法,暫停時間(STW)時間非常長,需要儘可能減少壓縮時間

G1原理及調優

1 G1簡介

G1(Garbage-First)是一款面向伺服器的垃圾收集器,支援新生代和老年代空間的垃圾收集,主要針對配備多核處理器及大容量記憶體的機器,G1最主要的設計目標是: 實現可預期及可配置的STW停頓時間

2 G1堆空間劃分

G1收集器堆空間

  • Region

為實現大記憶體空間的低停頓時間的回收,將劃分為多個大小相等的Region。每個小堆區都可能是 Eden區,Survivor區或者Old區,但是在同一時刻只能屬於某個代

在邏輯上, 所有的Eden區和Survivor區合起來就是新生代,所有的Old區合起來就是老年代,且新生代和老年代各自的記憶體Region區域由G1自動控制,不斷變動

  • 巨型物件

當物件大小超過Region的一半,則認為是巨型物件(Humongous Object),直接被分配到老年代的巨型物件區(Humongous regions),這些巨型區域是一個連續的區域集,每一個Region中最多有一個巨型物件,巨型物件可以佔多個Region

G1把堆記憶體劃分成一個個Region的意義在於:

  • 每次GC不必都去處理整個堆空間,而是每次只處理一部分Region,實現大容量記憶體的GC
  • 通過計算每個Region的回收價值,包括回收所需時間、可回收空間,在有限時間內儘可能回收更多的垃圾物件,把垃圾回收造成的停頓時間控制在預期配置的時間範圍內,這也是G1名稱的由來: garbage-first

3 G1工作模式

針對新生代和老年代,G1提供2種GC模式,Young GC和Mixed GC,兩種會導致Stop The World

  • Young GC 當新生代的空間不足時,G1觸發Young GC回收新生代空間 Young GC主要是對Eden區進行GC,它在Eden空間耗盡時觸發,基於分代回收思想和複製演算法,每次Young GC都會選定所有新生代的Region,同時計算下次Young GC所需的Eden區和Survivor區的空間,動態調整新生代所佔Region個數來控制Young GC開銷

  • Mixed GC 當老年代空間達到閾值會觸發Mixed GC,選定所有新生代裡的Region,根據全域性併發標記階段(下面介紹到)統計得出收集收益高的若干老年代 Region。在使用者指定的開銷目標範圍內,儘可能選擇收益高的老年代Region進行GC,通過選擇哪些老年代Region和選擇多少Region來控制Mixed GC開銷

4 全域性併發標記

全域性併發標記主要是為Mixed GC計算找出回收收益較高的Region區域,具體分為5個階段

全域性併發標記

  • 階段 1: 初始標記(Initial Mark) 暫停所有應用執行緒(STW),併發地進行標記從 GC Root 開始直接可達的物件(原生棧物件、全域性物件、JNI 物件),當達到觸發條件時,G1 並不會立即發起併發標記週期,而是等待下一次新生代收集,利用新生代收集的 STW 時間段,完成初始標記,這種方式稱為借道(Piggybacking)

  • 階段 2: 根區域掃描(Root Region Scan) 在初始標記暫停結束後,新生代收集也完成的物件複製到 Survivor 的工作,應用執行緒開始活躍起來; 此時為了保證標記演算法的正確性,所有新複製到 Survivor 分割槽的物件,需要找出哪些物件存在對老年代物件的引用,把這些物件標記成根(Root); 這個過程稱為根分割槽掃描(Root Region Scanning),同時掃描的 Suvivor 分割槽也被稱為根分割槽(Root Region); 根分割槽掃描必須在下一次新生代垃圾收集啟動前完成(接下來併發標記的過程中,可能會被若干次新生代垃圾收集打斷),因為每次 GC 會產生新的存活物件集合

  • 階段 3: 併發標記(Concurrent Marking) 標記執行緒與應用程式執行緒並行執行,標記各個堆中Region的存活物件資訊,這個步驟可能被新的 Young GC 打斷 所有的標記任務必須在堆滿前就完成掃描,如果併發標記耗時很長,那麼有可能在併發標記過程中,又經歷了幾次新生代收集

  • 階段 4: 再次標記(Remark) 和CMS類似暫停所有應用執行緒(STW),以完成標記過程短暫地停止應用執行緒, 標記在併發標記階段發生變化的物件,和所有未被標記的存活物件,同時完成存活資料計算

  • 階段 5: 清理(Cleanup) 為即將到來的轉移階段做準備, 此階段也為下一次標記執行所有必需的整理計算工作:

    • 整理更新每個Region各自的RSet(remember set,HashMap結構,記錄有哪些老年代物件指向本Region,key為指向本Region的物件的引用,value為指向本Region的具體Card區域,通過RSet可以確定Region中物件存活資訊,避免全堆掃描)
    • 回收不包含存活物件的Region
    • 統計計算回收收益高(基於釋放空間和暫停目標)的老年代分割槽集合

5 G1調優注意點

Full GC問題

G1的正常處理流程中沒有Full GC,只有在垃圾回收處理不過來(或者主動觸發)時才會出現, G1的Full GC就是單執行緒執行的Serial old gc,會導致非常長的STW,是調優的重點,需要儘量避免Full GC,常見原因如下:

  • 程式主動執行System.gc()
  • 全域性併發標記期間老年代空間被填滿(併發模式失敗)
  • Mixed GC期間老年代空間被填滿(晉升失敗)
  • Young GC時Survivor空間和老年代沒有足夠空間容納存活物件

類似CMS,常見的解決是:

  • 增大-XX:ConcGCThreads=n 選項增加併發標記執行緒的數量,或者STW期間並行執行緒的數量:-XX:ParallelGCThreads=n
  • 減小-XX:InitiatingHeapOccupancyPercent 提前啟動標記週期
  • 增大預留記憶體 -XX:G1ReservePercent=n ,預設值是10,代表使用10%的堆記憶體為預留記憶體,當Survivor區域沒有足夠空間容納新晉升物件時會嘗試使用預留記憶體

巨型物件分配

巨型物件區中的每個Region中包含一個巨型物件,剩餘空間不再利用,導致空間碎片化,當G1沒有合適空間分配巨型物件時,G1會啟動序列Full GC來釋放空間。可以通過增加 -XX:G1HeapRegionSize來增大Region大小,這樣一來,相當一部分的巨型物件就不再是巨型物件了,而是採用普通的分配方式

不要設定Young區的大小

原因是為了儘量滿足目標停頓時間,邏輯上的Young區會進行動態調整。如果設定了大小,則會覆蓋掉並且會禁用掉對停頓時間的控制

平均響應時間設定

使用應用的平均響應時間作為參考來設定MaxGCPauseMillis,JVM會盡量去滿足該條件,可能是90%的請求或者更多的響應時間在這之內, 但是並不代表是所有的請求都能滿足,平均響應時間設定過小會導致頻繁GC

調優方法與思路

如何分析系統JVM GC執行狀況及合理優化?

GC優化的核心思路在於:儘可能讓物件在新生代中分配和回收,儘量避免過多物件進入老年代,導致對老年代頻繁進行垃圾回收,同時給系統足夠的記憶體減少新生代垃圾回收次數,進行系統分析和優化也是圍繞著這個思路展開

1 分析系統的執行狀況

  • 系統每秒請求數、每個請求建立多少物件,佔用多少記憶體
  • Young GC觸發頻率、物件進入老年代的速率
  • 老年代佔用記憶體、Full GC觸發頻率、Full GC觸發的原因、長時間Full GC的原因

常用工具如下:

  • jstat jvm自帶命令列工具,可用於統計記憶體分配速率、GC次數,GC耗時,常用命令格式
jstat -gc <pid> <統計間隔時間>  <統計次數>

輸出返回值代表含義如下:

jstat

例如: jstat -gc 32683 1000 10 ,統計pid=32683的程序,每秒統計1次,統計10次

  • jmap jvm自帶命令列工具,可用於瞭解系統執行時的物件分佈,常用命令格式如下
// 命令列輸出類名、類數量數量,類佔用記憶體大小,
// 按照類佔用記憶體大小降序排列
jmap -histo <pid>

// 生成堆記憶體轉儲快照,在當前目錄下匯出dump.hrpof的二進位制檔案,
// 可以用eclipse的MAT圖形化工具分析
jmap -dump:live,format=b,file=dump.hprof <pid>
  • jinfo 命令格式
jinfo <pid> 

用來檢視正在執行的 Java 應用程式的擴充套件引數,包括Java System屬性和JVM命令列引數

其他GC工具

  • 監控告警系統:Zabbix、Prometheus、Open-Falcon
  • jdk自動實時記憶體監控工具:VisualVM
  • 堆外記憶體監控: Java VisualVM安裝Buffer Pools 外掛、google perf工具、Java NMT(Native Memory Tracking)工具
  • GC日誌分析:GCViewer、gceasy
  • GC引數檢查和優化:http://xxfox.perfma.com/

2 GC優化案例

  • 資料分析平臺系統頻繁Full GC

平臺主要對使用者在APP中行為進行定時分析統計,並支援報表匯出,使用CMS GC演算法。資料分析師在使用中發現系統頁面開啟經常卡頓,通過jstat命令發現系統每次Young GC後大約有10%的存活物件進入老年代。

原來是因為Survivor區空間設定過小,每次Young GC後存活物件在Survivor區域放不下,提前進入老年代,通過調大Survivor區,使得Survivor區可以容納Young GC後存活物件,物件在Survivor區經歷多次Young GC達到年齡閾值才進入老年代,調整之後每次Young GC後進入老年代的存活物件穩定執行時僅幾百Kb,Full GC頻率大大降低

  • 業務對接閘道器OOM

閘道器主要消費Kafka資料,進行資料處理計算然後轉發到另外的Kafka佇列,系統執行幾個小時候出現OOM,重啟系統幾個小時之後又OOM,通過jmap匯出堆記憶體,在eclipse MAT工具分析才找出原因:程式碼中將某個業務Kafka的topic資料進行日誌非同步列印,該業務資料量較大,大量物件堆積在記憶體中等待被列印,導致OOM

  • 賬號許可權管理系統頻繁長時間Full GC

系統對外提供各種賬號鑑權服務,使用時發現系統經常服務不可用,通過Zabbix的監控平臺監控發現系統頻繁發生長時間Full GC,且觸發時老年代的堆記憶體通常並沒有佔滿,發現原來是業務程式碼中呼叫了System.gc()

總結

GC問題可以說沒有捷徑,排查線上的效能問題本身就並不簡單,除了將本文介紹到的原理和工具融會貫通,還需要我們不斷去積累經驗,真正做到效能最優

篇幅所限,不再展開介紹常見GC引數的使用,我釋出在github:https://github.com/caison/caison-blog-demo

參考

《Java Performance: The Definitive Guide》 Scott Oaks

《深入理解 Java 虛擬機器:JVM 高階特性與最佳實踐(第二版》 周志華

Java效能調優實戰

Getting Started with the G1 Garbage Collector

GC參考手冊-Java版

請教G1演算法的原理——RednaxelaFX的回答

Java Hotspot G1 GC的一些關鍵技術——美團技術團隊

相關推薦

Java GC原理調

概述 本文介紹GC基礎原理和理論,GC調優方法思路和方法,基於Hotspot jdk1.8,學習之後將瞭解如何對生產系統出現的G

夯實Java基礎系列7:Java 程式碼塊執行順序

目錄 Java中的構造方法 構造方法簡介 構造方法例項 例 1 例 2 Java中的幾種構造方法詳解 普通構造方法 預設構造方法 過載構造方法 java子類構造方法呼叫父類構造方法 Java中的程式碼塊簡介 Java程式碼塊使用 區域性程式碼塊 構造程式碼塊 靜態程式碼塊 Java程式碼塊、

夯實Java基礎系列22:Java序列化反序列化

本系列文章將整理到我在GitHub上的《Java面試指南》倉庫,更多精彩內容請到我的倉庫裡檢視 https://github.com/h2pl/Java-Tutorial 喜歡的話麻煩點下Star哈 文章首發於我的個人部落格: www.how2playlife.com 本文參考 http://www

Java基本功」Java內部類的用法原理

實現接口 tcl 一點 print 定義 做成 這一 system clas 內部類初探 一、什麽是內部類?   內部類是指在一個外部類的內部再定義一個類。內部類作為外部類的一個成員,並且依附於外部類而存在的。內部類可為靜態,可用protected和private修飾(

java物件引用

Java物件及其引用  關於物件與引用之間的一些基本概念。         初學Java時,在很長一段時間裡,總覺得基本概念很模糊。後來才知道,在許多Java書中,把物件和物件的引用混為一談。可是,如果我分不清物件與

Java 11的ZGC為何如此高效

導讀:GC是大部分現代語言內建的特性,Java 11 新加入的ZGC號稱可以達到10ms 以下的 GC 停頓,本文作者對這一新功能進行了深入解析。同時還對還對這一新功能帶來的其他可能性做了展望。ZGC是否可以達到該效能目標,請看高可用架構志願者翻譯的文章。 Java 11的

GAN, pix2pix, CycleGANpix2pixHD

本文翻譯、總結自朱儁彥的線上報告,主要講了如何用機器學習生成圖片。 人員資訊 主講嘉賓 姓名:朱儁彥(Jun-Yan Zhu) 現狀:麻省理工學院博士後(PostDoc at MIT),電腦科學與人工智慧實驗室(Computer Science and A

JAVA 異常處理

jdk 如何 堆棧溢出 細節 fileread 空指針 note handle 優雅 JAVA 異常類型結構Error 和 Exeption受查異常和非受查異常異常的拋出與捕獲直接拋出異常封裝異常並拋出捕獲異常自定義異常try-catch-finallytry-with-r

Kubernetes APIServer 原理

## 前言 整個Kubernetes技術體系由宣告式API以及Controller構成,而kube-apiserver是Kubernetes的宣告式api server,併為其它元件互動提供了橋樑。因此加深對kube-apiserver的理解就顯得至關重要了。 ![](https://img2020.cn

Java基本功】String及其包裝類的實現原理

    String作為Java中最常用的引用型別,相對來說基本上都比較熟悉,無論在平時的編碼過程中還是在筆試面試中,String都很受到青睞,然而,在使用String過程中,又有較多需要注意的細節之處。   String的連線 @Testp

夯實Java基礎系列23:繼承、封裝、多型的底層實現原理

本系列文章將整理到我在GitHub上的《Java面試指南》倉庫,更多精彩內容請到我的倉庫裡檢視 https://github.com/h2pl/Java-Tutorial 喜歡的話麻煩點下Star哈 文章首發於我的個人部落格: www.how2playlife.com 從JVM結構開始談多型 Jav

Spring Boot、微服務架構大數據治理之間的故事

Springboot微服務架構 微服務的誕生並非偶然,它是在互聯網高速發展,技術日新月異的變化以及傳統架構無法適應快速變化等多重因素的推動下誕生的產物。互聯網時代的產品通常有兩類特點:需求變化快和用戶群體龐大,在這種情況下,如何從系統架構的角度出發,構建靈活、易擴展的系統,快速應對需求的變化;同時,隨著用戶的

從HTTP/0.9到HTTP/2:HTTP協議的歷史演變設計思路

eight 結果 key 視頻 this sso單點登陸 會有 研究 patch 本文原作者阮一峰,作者博客:ruanyifeng.com。 1、引言 HTTP 協議是最重要的互聯網基礎協議之一,它從最初的僅為瀏覽網頁的目的進化到現在,已經是短連接通信的事實工業標準,最新版

機器學習大殺器XGBoost原理

結構 近似算法 機器 form con gin fff .cn tran http://blog.itpub.net/31542119/viewspace-2199549/ XGBoost是boosting算法的其中一種。Boosting算法的思想是將許多弱分類器集成在

什麽是Java中的自動拆裝箱

.com 空指針異常 http har 三目運算 容器 ava eof 關系 基本數據類型 基本類型,或者叫做內置類型,是Java中不同於類(Class)的特殊類型。它們是我們編程中使用最頻繁的類型。 Java是一種強類型語言,第一次申明變量必須說明數據類型,第一次變量

充電寶usb接口電路及制作原理詳細

合規 其它 註意 pan 排列 ron 充電寶 需要 資料 轉自:http://www.elecfans.com/dianlutu/dianyuandianlu/20180511675801.html USB充電器套件,又名MP3/MP4充電器,輸入AC160-240V,5

通訊系統的均衡原理(時域均衡)

一、均衡的概念 二、均衡器的作用:校正或補償系統特性,減小碼間串擾的影響! 均衡器在系統中的位置: 三、均衡的分類: 一般情況下,頻域均衡器很難實現,現實或研究中,均衡一般都是指時域均衡器 下圖是一個橫向濾波器的時域均衡系統: 下面波形圖中,均衡的目標

塊狀元素內聯元素

很多剛入坑前端的同學一直不懂div和span兩個標籤有什麼區別。那麼,有什麼區別呢?答案就是div是塊狀元素,span是內聯元素。 那麼,塊狀元素(block)和內聯元素(inline)又有什麼區別呢?塊狀元素: 後面的元素會從另起一行開始 高度,行高以及頂、底邊距都可

spring boot 微服務的關係

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。 Spring Boot 和微服務沒關係, Java 微服務治理框架普遍用的是 Spring Cloud。 Spring Boot 產生的背景,是開發人員對 Spring 框架越來越複雜的配置吐槽越來越多,Pivotal 設計 Spring

JavaScriptECMAScript的區別

一文讀懂JavaScript和ECMAScript的區別 這篇文章代表了我目前對 JavaScript 和 ECMAScript 之間差異的理解。文章適合那些熟悉 JavaScript 但又想更加清楚地瞭解其與 ECMAScript、web 瀏覽器、Babel 等是何種關係的人。你還