翻看電腦的文件夾,無心看到了9月份在公司作的一次分享,瀏覽了一下"婆婆特",發現本身在ppt上的寫的引導性問題本身也不能確切的回答出來,哎,知識這東西,平時不經常使用的沒些日子就生疏了。因而,本小白決定把他整理下來,不敢班門弄斧,對於入門的同窗能夠快速瞭解虛擬機的大概,有錯誤的地方請批評指正。html
1、java虛擬機的內存結構java
public class ReferenceCountGc {程序員
public Object field = null;算法
public static void main(String[] args) {windows
ReferenceCountGc objA = new ReferenceCountGc();數組
ReferenceCountGc objB = new ReferenceCountGc();安全
objA.field = objB;多線程
objB.field = objA; app
objA = null;性能
objB = null;
System.gc();
}
}
當程序執行到System.gc()時,是否會回收對象objA和objB?
引用計數方法:給對象一個計數器,當對象被引用時就+1,釋放掉引用-1,當爲0時及不會再被引用。但引用計數方法的Bug是沒法解決對象循環引用的問題,但並非此算法沒有用武之地,在不少場景下會使用到這個算法。但java的垃圾回收並無使用。上面的程序若是使用的是引用計數算法則不會被回收,但虛擬機卻使用根搜索算法。
根搜索算法即設定一個對象稱爲GC root ,從這個節點向下進行搜索,搜索所走過的路徑稱爲引用鏈,當GC root沒有任何引用鏈相連即在圖論中不可到達,則證實此對象不可用
由此來看看,對象死後,垃圾回收算法;
標記-清除算法 複製算法
灰色矩形框爲可回收對象,標記-清除算法就是把可回收的對象進行標記,標記到必定次數則清除掉。從圖中能夠明顯看出,該算法的弊端是會產生大量的磁盤碎片,沒有一整片連續的空間,當遇到佔用連續的內存空間較多的對象時,因爲內存放不下該對象,會提早進行垃圾回收,導致虛擬機垃圾回收頻繁,影響性能
爲了規避標記清除算法的弊端,出現了複製算法,複製算法將內存一份爲二,垃圾回收時將使用的內存中的存活對象,拷貝到另外一半內存中,而後把左側內存區域徹底清除掉,上圖只是演示了複製算法,但並不是一分爲二,使用和保留的空間是1:1,能夠根據實際狀況對虛擬機參數進行調整。此算法的弊端是要保留內存空間,會將可用內存變少。
標記整理算法: 分代收集算法:
標記整理算法:綠色和藍色區域都表明存活對象,當進行垃圾回收時把存活對象依次移到最左邊,移動後將其他內存空間清空。
分代收集算法:如圖,其實就是沒有算法。。。把以上3種算法進行綜合運用,前面說過堆是有劃分的,簡單分爲新生代和老年代,分代收集就是根據不一樣代的特色應用不一樣的垃圾回收算法。
3、java內存分配
java的自動內存管理解決了兩個問題,一是給對象分配內存,二是回收分配給對象的內存,前面咱們講了回收分配給對象的內存,下面咱們來看看給對象分配內存
java堆分爲新生代,老年代(終身代)和永久代。
新生代和老年代的默認比值爲1:2即新生代佔堆總內存的1/3,能夠經過 –Xms(初始堆大小)、-Xmx (最大堆大小)來改變。
新生代又分爲Eden區、From survivor區、To survivor區,Eden:From:To 爲 8:1:1,能夠經過–XX:SurvivorRatio 參數設定。
JVM每次只會使用From區和survivor區中的一塊(Form survivor或To survivor),很明顯是爲了在垃圾回收的時候將存活對象移到另一個空閒的survivor區(若是空間足夠,不然直接進入老年代),所以垃圾回收所使用的算法是複製算法。
新生的對象會被分配到新生代,新生代的特色是朝生夕死,對象存活的時間短,迭代快。發生在新生代的垃圾回收叫minor GC,minor Gc進行的相對頻繁,消耗較full GC少,而Full GC是發生在老年代的垃圾回收,採用的是標記-清除算法。老年代進行一次垃圾回收比新生代話費時間長,進行的也沒有老年代頻繁,同時要儘可能減小老年代的垃圾回收,由於回收速度慢且在進行時影響虛擬機性能,使虛擬機響應變慢,最直接的感受是應用程序的響應速度變慢。
什麼狀況下,對象會被分配到老年代?
從上圖中明顯能夠到3點:
大對象:什麼是大對象,大對象就是須要連續佔用不少內存空間的對象好比很長的字符串和數組。虛擬機經過-XX:PretrnureSizeThreshold設計大過指定大小的對象之間進入老年代,即時沒有超過指定大小,在進行minor GC時一般也會由於survivor區不夠用而被轉移到老年代。
經過設置MaxTenuringThreshold參數: 這個參數是進行年齡設置的,超過這個年齡的會進入老年代。什麼是年齡?在新生代進行minor GC的時候,每進行一次,存活下來的對象年齡+1,默認年齡超過15的會進入老年代。15這個數值也能夠經過MaxTenuringThreshold參數改變。
Survivor空間中相同年齡全部對象大小的總和大於survivor空間的一半,全部大於或者等於該年齡的對象直接進入老年代,這句話比較拗口,但就是這個意思,看不懂的多看幾遍就行了。。。
前面講了這麼多參數,如何設置虛擬機參數?能夠經過IDE進行設置,不管是調整空間大小,仍是設置對象的年齡進入老年代,以下圖
3、咱們開發中應注意的問題
從虛擬機上能夠看出,主要是避免full GC的次數,減小朝生夕死的大對象,對虛擬機內存進行優化,在平常開發中寫程序的主要注意的是
不要使用長字符串 如:String x = new String(「XXXXXXXXXXXX」) StringBuffer stringBuffer = new StringBuffer()StringBuffer對象的append()方法。固然,考慮到線程安全問題,使用StringBuilder.