中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

老生常談java垃圾回收算法(必看篇)

發布時間:2020-09-08 23:39:40 來源:腳本之家 閱讀:159 作者:jingxian 欄目:編程語言

1.引用計數法(Reference Counting Collector)

1.1算法分析

引用計數是垃圾收集器中的早期策略。在這種方法中,堆中每個對象實例都有一個引用計數。當一個對象被創建時,且將該對象實例分配給一個變量,該變量計數設置為1。當任何其它變量被賦值為這個對象的引用時,計數加1(a = b,則b引用的對象實例的計數器+1),但當一個對象實例的某個引用超過了生命周期或者被設置為一個新值時,對象實例的引用計數器減1。任何引用計數器為0的對象實例可以被當作垃圾收集。當一個對象實例被垃圾收集時,它引用的任何對象實例的引用計數器減1。

1.2優缺點

優點:

引用計數收集器可以很快的執行,交織在程序運行中。對程序需要不被長時間打斷的實時環境比較有利。

缺點:

無法檢測出循環引用。如父對象有一個對子對象的引用,子對象反過來引用父對象。這樣,他們的引用計數永遠不可能為0.

1.3引用計數算法無法解決循環引用問題,例如:

public class Main {
 public static void main(String[] args) {
  MyObject object1 = new MyObject();
  MyObject object2 = new MyObject();
   
  object1.object = object2;
  object2.object = object1;
   
  object1 = null;
  object2 = null;
 }
}

最后面兩句將object1和object2賦值為null,也就是說object1和object2指向的對象已經不可能再被訪問,但是由于它們互相引用對方,導致它們的引用計數器都不為0,那么垃圾收集器就永遠不會回收它們。

2.Mark-Sweep(標記-清除)Tracing Collector(tracing算法)

這是最基礎的垃圾回收算法,之所以說它是最基礎的是因為它最容易實現,思想也是最簡單的。標記-清除算法分為兩個階段:標記階段和清除階段。標記階段的任務是標記出所有需要被回收的對象,清除階段就是回收被標記的對象所占用的空間。具體過程如下圖所示:

老生常談java垃圾回收算法(必看篇)

從圖中可以很容易看出標記-清除算法實現起來比較容易,但是有一個比較嚴重的問題就是容易產生內存碎片,碎片太多可能會導致后續過程中需要為大對象分配空間時無法找到足夠的空間而提前觸發新的一次垃圾收集動作。

3.Copying(復制)算法

為了解決Mark-Sweep算法的缺陷,Copying算法就被提了出來。它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然后再把已使用的內存空間一次清理掉,這樣一來就不容易出現內存碎片的問題。具體過程如下圖所示:

老生常談java垃圾回收算法(必看篇)

這種算法雖然實現簡單,運行高效且不容易產生內存碎片,但是卻對內存空間的使用做出了高昂的代價,因為能夠使用的內存縮減到原來的一半。

很顯然,Copying算法的效率跟存活對象的數目多少有很大的關系,如果存活對象很多,那么Copying算法的效率將會大大降低。

4.Mark-Compact(標記-整理)算法

為了解決Copying算法的缺陷,充分利用內存空間,提出了Mark-Compact算法。該算法標記階段和Mark-Sweep一樣,但是在完成標記之后,它不是直接清理可回收對象,而是將存活對象都向一端移動,然后清理掉端邊界以外的內存。具體過程如下圖所示:

老生常談java垃圾回收算法(必看篇)

  

5.Generational Collection(分代收集)算法

分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根據對象存活的生命周期將內存劃分為若干個不同的區域。一般情況下將堆區劃分為老年代(Tenured Generation)和新生代(Young Generation),老年代的特點是每次垃圾收集時只有少量對象需要被回收,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據不同代的特點采取最適合的收集算法。

目前大部分垃圾收集器對于新生代都采取Copying算法,因為新生代中每次垃圾回收都要回收大部分對象,也就是說需要復制的操作次數較少,但是實際中并不是按照1:1的比例來劃分新生代的空間的,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的對象復制到另一塊Survivor空間中,然后清理掉Eden和剛才使用過的Survivor空間。

而由于老年代的特點是每次回收都只回收少量對象,一般使用的是Mark-Compact算法。

注意,在堆區之外還有一個代就是永久代(Permanet Generation),它用來存儲class類、常量、方法描述等。對永久代的回收主要回收兩部分內容:廢棄常量和無用的類。

垃圾收集器

新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge

老年代收集器使用的收集器:Serial Old、Parallel Old、CMS

老生常談java垃圾回收算法(必看篇)

Serial收集器(復制算法)

新生代單線程收集器,標記和清理都是單線程,優點是簡單高效。

Serial Old收集器(標記-整理算法)

老年代單線程收集器,Serial收集器的老年代版本。

ParNew收集器(停止-復制算法) 

新生代收集器,可以認為是Serial收集器的多線程版本,在多核CPU環境下有著比Serial更好的表現。

Parallel Scavenge收集器(停止-復制算法)

并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般為99%, 吞吐量= 用戶線程時間/(用戶線程時間+GC線程時間)。適合后臺應用等對交互相應要求不高的場景。

Parallel Old收集器(停止-復制算法)

Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量優先

CMS(Concurrent Mark Sweep)收集器(標記-清理算法)

高并發、低停頓,追求最短GC回收停頓時間,cpu占用比較高,響應時間快,停頓時間短,多核cpu 追求高響應時間的選擇

GC的執行機制

由于對象進行了分代處理,因此垃圾回收區域、時間也不一樣。GC有兩種類型:Scavenge GC和Full GC。

Scavenge GC

一般情況下,當新對象生成,并且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,并且把尚且存活的對象移動到Survivor區。然后整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。因為大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,所以Eden區的GC會頻繁進行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。

Full GC

對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個堆進行回收,所以比Scavenge GC要慢,因此應該盡可能減少Full GC的次數。在對JVM調優的過程中,很大一部分工作就是對于FullGC的調節。有如下原因可能導致Full GC:

1.年老代(Tenured)被寫滿

2.持久代(Perm)被寫滿

3.System.gc()被顯示調用

4.上一次GC之后Heap的各域分配策略動態變化

Java有了GC同樣會出現內存泄露問題

靜態集合類像HashMap、Vector等的使用最容易出現內存泄露,這些靜態變量的生命周期和應用程序一致,所有的對象Object也不能被釋放,因為他們也將一直被Vector等應用著。

Static Vector v = new Vector(); 
for (int i = 1; i<100; i++) 
{ 
 Object o = new Object(); 
 v.add(o); 
 o = null; 
}

在這個例子中,代碼棧中存在Vector 對象的引用 v 和 Object 對象的引用 o 。在 For 循環中,我們不斷的生成新的對象,然后將其添加到 Vector 對象中,之后將 o 引用置空。問題是當 o 引用被置空后,如果發生 GC,我們創建的 Object 對象是否能夠被 GC 回收呢?答案是否定的。因為, GC 在跟蹤代碼棧中的引用時,會發現 v 引用,而繼續往下跟蹤,就會發現 v 引用指向的內存空間中又存在指向 Object 對象的引用。也就是說盡管o 引用已經被置空,但是 Object 對象仍然存在其他的引用,是可以被訪問到的,所以 GC 無法將其釋放掉。如果在此循環之后, Object 對象對程序已經沒有任何作用,那么我們就認為此 Java 程序發生了內存泄漏。

2.各種連接,數據庫連接,網絡連接,IO連接等沒有顯示調用close關閉,不被GC回收導致內存泄露。

3.監聽器的使用,在釋放對象的同時沒有相應刪除監聽器的時候也可能導致內存泄露。

以上這篇(標題)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海兴县| 呈贡县| 永宁县| 萍乡市| 乃东县| 刚察县| 博野县| 屏南县| 比如县| 岑溪市| 师宗县| 渑池县| 大港区| 西和县| 华蓥市| 中江县| 奈曼旗| 苗栗市| 荆州市| 永年县| 庐江县| 于田县| 抚松县| 九龙坡区| 肇东市| 洛隆县| 牙克石市| 星子县| 郴州市| 安阳市| 师宗县| 富平县| 海丰县| 武胜县| 安宁市| 江津市| 新密市| 郑州市| 高密市| 达州市| 霞浦县|