gc(garbage collection)是我們在學習 jvm 的過程中不可避免的一道坎,接下來,我們就來系統的學習一下 gc。
做一件事情之前,我們一定要去知道我們為什麼要去做,這裡不僅僅指 gc,更適用我們日常的學習和生活,知其然,知其所以然,方能百戰不殆。
下面我們先去了解為什麼要有 gc,以及 gc 在 jvm 中扮演了乙個什麼樣的角色,起到了什麼的作用?
用過 c++ 的同學可能知道,物件所佔的內存在程式結束執行之前一直被占用,在明確釋放之前不能分配給其它物件。如果我們不去手動的清除這些無用的物件,記憶體很快就被佔滿,而在 jvm 中,gc 所起到的作用就是乙個清道夫,它可以幫助我們去判定哪些物件是無用物件,怎麼進行垃圾收集,以及決定記憶體分代和記憶體分配的策略**。
可能有同學會問了,既然我們的 jvm 會給我們做 gc 的工作,我們為什麼還要去學習 gc 呢,一切交給 jvm 不好嗎?當然,在我們的日常情況下,我們一般不會去關心 gc 的一些細節,但是當我們遇到記憶體洩露,記憶體溢位,高併發瓶頸的時候,我們就需要去對 gc 開刀,進行更為細緻的監控和調節。
記憶體洩露:指程式中己動態分配的堆記憶體由於某種原因程式未釋放或無法釋放,造成系統記憶體的浪費,導致程式執行速度減慢甚至系統崩潰等嚴重後果。那麼現在問題來了,我們要進行垃圾**,首先我們需要知道垃圾在哪記憶體溢位:應用系統中存在無法**的記憶體或使用的記憶體過多,最終使得程式執行要用到的記憶體大於能提供的最大記憶體。
前面我們講了jvm 的執行時記憶體區域,知道執行緒可以分為執行緒獨佔區和執行緒共享區,其中執行緒獨佔區(程式計數器,虛擬機器棧,本地方法棧)的記憶體生命週期是和執行緒保持一致,且這幾個區域分配的記憶體大小跟類的大小有關,也就是說,當我們的類結構固定之後,這部分的記憶體就不會再發生更改,且當方法或執行緒結束的時候,記憶體自然就跟隨著**了.
而執行緒共享區的堆記憶體和方法區則不一樣,堆記憶體和方法區所用的記憶體是在編譯期間無法確定的,因為乙個介面的不同實現,乙個方法的不同控制條件分支所執行的**可能完全相反,我們只有在執行時才知道會建立哪些物件,這部分的記憶體的分配和**是動態的,而我們的 gc 關注的就是該部分的記憶體。
打個比方來說:jvm 如果是一輛車,執行緒獨佔區的就像是零件,在出廠時這些零件的壽命基本上都是已知的,執行緒共享區就像是汽油,汽油的消耗跟我們所採用的路線有關,所以我們關注的部分就是這部分會動態變化的,比如如何開車才能更省油~
知道了垃圾在什麼位置會出現,我們下一步就需要去判定在這些區域的有哪些是垃圾~
本節內容到這裡先告一段落,下一節我們來學習,怎麼去判定是否為垃圾~
五分鐘玩轉git
許多人認為git太混亂,或認為它是一種複雜的版本控制系統,其實不然,這篇文章有助於大家快速上手使用git。使用git前,需要先建立乙個倉庫 repository 您可以使用乙個已經存在的目錄作為git倉庫或建立乙個空目錄。使用您當前目錄作為git倉庫,我們只需使它初始化。git init使用我們指定...
每日五分鐘,玩轉JVM 兩種演算法
上篇文章,我們了解了gc 的相關概念,這篇文章我們通過兩個演算法來了解如何去確定堆中的物件例項哪些是我們需要去 的垃圾物件。引用計數法的原理很簡單,就是在物件中維護乙個計數器,當有乙個物件引用它的時候,該計數器的值就會加一,當這個引用失效的時候,計數器的值就會減少一,當計數器的值為零的時候,就意味著...
五分鐘帶你玩轉rocketMQ(五)實戰廣播與集群
1.集群消費方式 乙個consumergroup中的consumer例項平均分攤消費生產者傳送的訊息。例如某個topic有九條訊息,其中乙個consumer group有三個例項 可能是3個程序,或者3臺機器 那麼每個例項只消費其中的3條訊息,consumer不指定消費方式的話預設是集群消費的,適用...