JVM內存管理

內存區域

Java的內存區域主要包括虛擬機棧,本地方法棧,程序計數器,堆,方法區。

虛擬機棧 是對應於每個線程運行時候的東西,JVM會給每個線程分配一個棧,線程運行就是執行棧裏面的東西。這個棧又包含了幀,幀對應着線程函數。棧裏面只能夠出幀和入幀,對應着每個函數的運行和運行完成。

本地方法棧 是每個線程native代碼對應的部分。與虛擬機棧很相似,但是本地方法棧執行的是Java Native方法。

程序計數器 可以看作是當前線程執行字節碼的行號指示器。字節碼解釋器可以通過改變程序計數器的值來選取下一條需要執行的指令。分支,循環,跳轉都需要這個計數器來實現。

JAVA堆 是所有線程共享的,每次new的時候,JVM就會在Java堆裏面劃一塊區域。平時的內存溢出也基本都是這塊區域超出了。

JAVA方法區 是存儲着已經加載的類,常量,靜態變量等數據。方法區,也常被稱作永久代,方法區很少進行垃圾回收,回收也非常嚴苛。如果這個區域出現異常,則一般會提示PermGen space。

引用

Java中有四種引用,強引用,軟引用,弱引用,虛引用。JVM對每種類型的回收是不一致的。

強引用是Java中最常見的,一般我們使用的Object object = new Object就是強引用。一個對象只要存在強引用,對象就不會被回收,如果內存不夠,就拋出OutOfMemory異常。

軟引用是如果一個對象只有軟引用,那麼在內存足夠的時候對象不會回收該對象,如果內存不夠的時候對象就會被回收。軟引用適合作高速緩存。

軟引用可以和引用隊列一起使用,當引用對象被回收的時候,會被虛擬機加入到引用隊列裏面去。

SoftReference<Object> softObject = new SoftReference(new Object(),new ReferenceQueue<Object>())

弱引用是一個對象如果只有弱引用,那麼對象在下次垃圾回收的時候,不管內存足不足夠都會被回收。它比軟引用的週期更短,不過垃圾回收是一個優先級非常低的線程,對象實際上被回收也不會那麼快。它也可以跟一個引用隊列一起使用。

虛引用是一個更加弱小的引用,只有虛引用的對象不知道對象什麼時候會被回收。它主要用來跟蹤對象被垃圾回收的活動。它一定要跟一個引用隊列一起使用。

垃圾回收

Java會有一個單獨垃圾回收進程,對虛擬機在程序新建的但已經沒有用的對象進行回收。對於如何判斷對象是否還在使用,這裏面有兩種常見的方式是引用計數法跟可達性分析法。引用計數法通過給每個對象的引用進行計數,這種方式很簡單,並且效率高。但是在解決循環引用的時候效果並不好。而主流的編程語言都是採用可達性分析法來進行對象是否還有用的判斷的,可達性分析法通過一系列的“GC ROOT”對象,通過其引用的對象以及這些對象的引用不斷地循環擴展,構成一顆引用樹,那些沒有在這顆樹上的對象就是沒有用的,可以被回收的對象了。

垃圾收集算法有很多,像標記清除算法,複製算法,標記整理算法,分代收集算法等等。

內存分配策略

JVM在內存分配的時候遵循着一些規則:

  1. 對象優先分配在Eden區
  2. 大對象直接分配在老年代,老年代的回收是非常少的,老年代的回收是一次Full GC。
  3. 長期存活的對象進入老年代
  4. 動態對對象年齡的判斷,如果Eden區有相同年齡的對象內存之和超過新生代空間一半,則將年齡超過這些年齡相同對象的對象都移到老年區
  5. 空間分配擔保,在進行minor GC前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代所有對象的總空間,如果大於則直接GC,如果不大於,則要根據之前新生代到老年代的對象的平均大小來判斷,如果老年代連續可用空間比平均大小大,則繼續minor GC,如果不大,則進行一次Full GC。
    內存代,新生代,老年代,永久代
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章