JVM 報 GC Overhead limit exceeded 是什麼意思?
阿新 • • 發佈:2021-02-15
預設情況下,並不是等堆記憶體耗盡,才會報 OutOfMemoryError,而是如果 JVM 覺得 GC 效率不高,也會報這個錯誤。
那麼怎麼評價 GC 效率不高呢?來看下原始碼:
呢?來看下原始碼gcOverheadChecker.cpp:
void GCOverheadChecker::check_gc_overhead_limit(GCOverheadTester* time_overhead, GCOverheadTester* space_overhead, bool is_full_gc, GCCause::Cause gc_cause, SoftRefPolicy* soft_ref_policy) { // 忽略顯式gc命令,比如System.gc(),或者通過JVMTI命令的gc,或者通過jcmd命令的gc if (GCCause::is_user_requested_gc(gc_cause) || GCCause::is_serviceability_requested_gc(gc_cause)) { return; } bool print_gc_overhead_limit_would_be_exceeded = false; if (is_full_gc) { //如果gc時間過長,並且gc回收的空間還是不多 //gc時間佔用98%以上為gc時間過長,可以通過 -XX:GCTimeLimit= 配置,參考gc_globals.hpp: GCTimeLimit //回收空間小於2%為gc回收空間不多,可以通過 -XX:GCHeapFreeLimit= 配置,參考gc_globals.hpp: GCHeapFreeLimit if (time_overhead->is_exceeded() && space_overhead->is_exceeded()) { _gc_overhead_limit_count++; //如果UseGCOverheadLimit這個狀態位為開啟 //預設情況下,是開啟的,可以通過啟動引數-XX:-UseGCOverheadLimit關閉,參考:gc_globals.hpp: UseGCOverheadLimit if (UseGCOverheadLimit) { //如果超過規定次數,這個次數預設不可配置,必須開啟develop編譯jdk才能配置,參考gc_globals.hpp: GCOverheadLimitThreshold if (_gc_overhead_limit_count >= GCOverheadLimitThreshold){ //設定狀態位,準備丟擲OOM set_gc_overhead_limit_exceeded(true); //清空計數 reset_gc_overhead_limit_count(); } else { //如果還沒到達次數,但是也快到達的時候,清空所有的軟引用 bool near_limit = gc_overhead_limit_near(); if (near_limit) { soft_ref_policy->set_should_clear_all_soft_refs(true); log_trace(gc, ergo)("Nearing GC overhead limit, will be clearing all SoftReference"); } } } //需要列印日誌,提示GC效率不高 print_gc_overhead_limit_would_be_exceeded = true; } else { // Did not exceed overhead limits reset_gc_overhead_limit_count(); } } if (UseGCOverheadLimit) { if (gc_overhead_limit_exceeded()) { log_trace(gc, ergo)("GC is exceeding overhead limit of " UINTX_FORMAT "%%", GCTimeLimit); reset_gc_overhead_limit_count(); } else if (print_gc_overhead_limit_would_be_exceeded) { assert(_gc_overhead_limit_count > 0, "Should not be printing"); log_trace(gc, ergo)("GC would exceed overhead limit of " UINTX_FORMAT "%% %d consecutive time(s)", GCTimeLimit, _gc_overhead_limit_count); } } }
預設配置:gc_globals.hpp
product(bool, UseGCOverheadLimit, true, \ "Use policy to limit of proportion of time spent in GC " \ "before an OutOfMemory error is thrown") \ \ product(uintx, GCTimeLimit, 98, \ "Limit of the proportion of time spent in GC before " \ "an OutOfMemoryError is thrown (used with GCHeapFreeLimit)") \ range(0, 100) \ \ product(uintx, GCHeapFreeLimit, 2, \ "Minimum percentage of free space after a full GC before an " \ "OutOfMemoryError is thrown (used with GCTimeLimit)") \ range(0, 100) \ \ develop(uintx, GCOverheadLimitThreshold, 5, \ "Number of consecutive collections before gc time limit fires") \ range(1, max_uintx)
可以總結出:預設情況下,啟用了 UseGCOverheadLimit,連續 5 次,碰到 GC 時間佔比超過 98%,GC 回收的記憶體不足 2% 時,會丟擲這個異常。
微信搜尋“我的程式設計喵”關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer: