天天看點

GC 垃圾回收 和 垃圾回收器

什麼是垃圾?

沒有任何引用指向的對象就是垃圾

怎麼找到一個垃圾?

常用的技術一:引用計數

記錄目前的空間有多少個對象在引用,當數值變成一了,就垃圾回收

常用的技術二:根可達算法

哪些對象是根對象?

jvm stack

native

method

pool 等等

如何清除一個垃圾?

一共就三種算法

  • Mark-Sweep 标記清除
  • Copying 拷貝
  • Mark-Compact 标記壓縮

Mark-Sweep

GC 垃圾回收 和 垃圾回收器

優點:簡單

缺點:碎片化,所謂的碎片化就是指的一個空間裡清除的區域東一個西一個,千瘡百孔,找不到一個連續的空間存儲

Copying

GC 垃圾回收 和 垃圾回收器

規定空間隻能使用一半,将資料存儲之後,然後将另外一半 複制過去

缺點:浪費空間

Mark-Compact

GC 垃圾回收 和 垃圾回收器

先把要回收的弄到一塊區域,集中回收

缺點:效率低

☆☆☆Garbage collectors 垃圾回收器☆☆

新生代 和 老年代?

每經過一個垃圾收集器處理,年齡加1,回收過好幾遍都回收不掉的稱為老年代

PS + PO

GC 垃圾回收 和 垃圾回收器

經常配合使用的是:

parnew 和 cms

serial 和 serial old

PS 和 PO

堆記憶體邏輯分區

GC 垃圾回收 和 垃圾回收器

新産生的對象都會存才Eden區域,但是采用的是複制算法,淘汰的對象很多,隻有少部分資料可以進入 survivor區域,survivor區域總有一個是空的。

預設新生代和老年代的占空間大小為1:2,老年代空間要大些,可以自己調節。大小調節不規範就會産生很多問題,比如後面的full gc

GC 垃圾回收 和 垃圾回收器

Serial

STW: stop-the-world :立刻停止事件

停止之後進行垃圾回收,停止時間從幾秒可以到3天

JVM第一個調優:重新開機

CMS:承前啟後

工作在老年代,mark sweep 碎片化

暫停時間很短

并發執行:垃圾回收線程和工作線程同時執行

沖突:

有些垃圾在某些情況下又不是垃圾了

GC 垃圾回收 和 垃圾回收器

記憶體比較少的時候,serial和serial old配合

記憶體越來越大,parallel scavenge 和 parallel old 配合

記憶體更大的時候,parnew 和CMS配合

cms有一個巨大的毛病:用通俗的話來說,可能會産生一個阿姨打掃整個100層樓的酒店情況,會非常的 耗時

jdk 1.8預設的回收機制:PS/PO

jdk 1.8以上預設回收機制:G1

什麼是調優

1、。。。。。

2、優化jvm的運作環境

3、解決jvm運作時出現的問題(OOM:記憶體洩漏)

了解記憶體洩漏:這空間被占用,無法進行回收

記憶體溢出:占滿了,回收不了,記憶體崩了

處理cpu記憶體異常的工具:arthas

GC 垃圾回收 和 垃圾回收器

問題:線上運作的程式,cpu突然飙高,你怎麼解決這個問題?

GC 垃圾回收 和 垃圾回收器

定位線程

我們知道,Java是單程序多線程的,那麼,我們接下來看看PID=xxxx的這個Java程序中的各個線程的CPU使用情況,同樣是用top指令:

GC 垃圾回收 和 垃圾回收器

定位代碼

通過top指令,我們目前已經定位到導緻CPU使用率較高的具體線程, 那麼我麼接下來就定位下到底是哪一行代碼存在問題。

首先,我們需要把4519這個線程轉成16進制:

GC 垃圾回收 和 垃圾回收器
GC 垃圾回收 和 垃圾回收器

查找出哪些對象回收不了?

可以查找出哪些對象的實占記憶體最多

GC 垃圾回收 和 垃圾回收器
GC 垃圾回收 和 垃圾回收器

項目頻繁的full gc 你該怎麼做?

觸發原因有很多種,但歸根到底都是因為記憶體空間不足了

Full GC頻繁發生,意味着你的記憶體配置設定機制存在問題,也許是記憶體洩露,有大量記憶體垃圾不斷在老年代産生;也許是你的大對象(緩存)過多;也有可能是你的參數設定不好,minor GC清理不掉記憶體,導緻每次minor GC都會觸發Full GC;還有可能是你的老年代大小參數設定錯誤,老年代過小等等原因

1、如果每次gc之後剩餘的空間不大,說明有一部分頑固對象一直沒法被回收,導緻可用記憶體變少。這種情況下很容易後續出現oom,比如說一次大對象的申請

2、如果每次gc之後剩餘的空間比較大,意味着大部分對象都被清理了,但是系統又在頻繁的fullgc,說明很快老年代又會湧入大量對象。這個時候就應該檢查下jvm的參數配置,很有可能是新生代設定的太小了,導緻很多應該在minor gc階段就清理出去的對象留到了老年代,這種可能性是最大的

新生代可以分為eden、survivor0、survivor1,正常的對象配置設定都是在eden完成的,如果eden空間不夠了,會觸發一次minor gc,存活的對象放在s0或s1中。随着每次minor gc,存活的對象會不斷的從s0遷到s1,再從s1遷到s0,這個過程經過幾次之後,如果對象還是存活的,就會晉升到老年代。

但如果新生代大小設定的太小,就會導緻非常頻繁的minor gc,s0->s1來回切換的速度加快,導緻本身應該在minor gc就清理出去的對象跑到了老年代。

舉個例子,正常情況下如果minor gc是1分鐘一次,-XX:MaxTenuringThreshold預設配置是15的話,正常的小對象最長可以在新生代待15分鐘左右,如果一個對象o的存活時間是5分鐘,那它就可以在minor gc的時候被清理出去;但如果新生代設定過小,minor gc的頻率降到10秒一次,那麼o隻能在新生代待150秒左右,然後就會晉升到老年代,這種對象一多,就會導緻頻繁的fullgc