欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2017年05月19日 08:30:33   投稿:jingxian  
下面小編就為大家?guī)硪黄仙U刯ava垃圾回收算法(必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

1.引用計(jì)數(shù)法(Reference Counting Collector)

1.1算法分析

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

1.2優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

引用計(jì)數(shù)收集器可以很快的執(zhí)行,交織在程序運(yùn)行中。對(duì)程序需要不被長時(shí)間打斷的實(shí)時(shí)環(huán)境比較有利。

缺點(diǎn):

無法檢測(cè)出循環(huán)引用。如父對(duì)象有一個(gè)對(duì)子對(duì)象的引用,子對(duì)象反過來引用父對(duì)象。這樣,他們的引用計(jì)數(shù)永遠(yuǎn)不可能為0.

1.3引用計(jì)數(shù)算法無法解決循環(huán)引用問題,例如:

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指向的對(duì)象已經(jīng)不可能再被訪問,但是由于它們互相引用對(duì)方,導(dǎo)致它們的引用計(jì)數(shù)器都不為0,那么垃圾收集器就永遠(yuǎn)不會(huì)回收它們。

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

這是最基礎(chǔ)的垃圾回收算法,之所以說它是最基礎(chǔ)的是因?yàn)樗钊菀讓?shí)現(xiàn),思想也是最簡(jiǎn)單的。標(biāo)記-清除算法分為兩個(gè)階段:標(biāo)記階段和清除階段。標(biāo)記階段的任務(wù)是標(biāo)記出所有需要被回收的對(duì)象,清除階段就是回收被標(biāo)記的對(duì)象所占用的空間。具體過程如下圖所示:

從圖中可以很容易看出標(biāo)記-清除算法實(shí)現(xiàn)起來比較容易,但是有一個(gè)比較嚴(yán)重的問題就是容易產(chǎn)生內(nèi)存碎片,碎片太多可能會(huì)導(dǎo)致后續(xù)過程中需要為大對(duì)象分配空間時(shí)無法找到足夠的空間而提前觸發(fā)新的一次垃圾收集動(dòng)作。

3.Copying(復(fù)制)算法

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

這種算法雖然實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效且不容易產(chǎn)生內(nèi)存碎片,但是卻對(duì)內(nèi)存空間的使用做出了高昂的代價(jià),因?yàn)槟軌蚴褂玫膬?nèi)存縮減到原來的一半。

很顯然,Copying算法的效率跟存活對(duì)象的數(shù)目多少有很大的關(guān)系,如果存活對(duì)象很多,那么Copying算法的效率將會(huì)大大降低。

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

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

  

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

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

目前大部分垃圾收集器對(duì)于新生代都采取Copying算法,因?yàn)樾律忻看卫厥斩家厥沾蟛糠謱?duì)象,也就是說需要復(fù)制的操作次數(shù)較少,但是實(shí)際中并不是按照1:1的比例來劃分新生代的空間的,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當(dāng)進(jìn)行回收時(shí),將Eden和Survivor中還存活的對(duì)象復(fù)制到另一塊Survivor空間中,然后清理掉Eden和剛才使用過的Survivor空間。

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

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

垃圾收集器

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

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

Serial收集器(復(fù)制算法)

新生代單線程收集器,標(biāo)記和清理都是單線程,優(yōu)點(diǎn)是簡(jiǎn)單高效。

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

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

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

新生代收集器,可以認(rèn)為是Serial收集器的多線程版本,在多核CPU環(huán)境下有著比Serial更好的表現(xiàn)。

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

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

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

Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量優(yōu)先

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

高并發(fā)、低停頓,追求最短GC回收停頓時(shí)間,cpu占用比較高,響應(yīng)時(shí)間快,停頓時(shí)間短,多核cpu 追求高響應(yīng)時(shí)間的選擇

GC的執(zhí)行機(jī)制

由于對(duì)象進(jìn)行了分代處理,因此垃圾回收區(qū)域、時(shí)間也不一樣。GC有兩種類型:Scavenge GC和Full GC。

Scavenge GC

一般情況下,當(dāng)新對(duì)象生成,并且在Eden申請(qǐng)空間失敗時(shí),就會(huì)觸發(fā)Scavenge GC,對(duì)Eden區(qū)域進(jìn)行GC,清除非存活對(duì)象,并且把尚且存活的對(duì)象移動(dòng)到Survivor區(qū)。然后整理Survivor的兩個(gè)區(qū)。這種方式的GC是對(duì)年輕代的Eden區(qū)進(jìn)行,不會(huì)影響到年老代。因?yàn)榇蟛糠謱?duì)象都是從Eden區(qū)開始的,同時(shí)Eden區(qū)不會(huì)分配的很大,所以Eden區(qū)的GC會(huì)頻繁進(jìn)行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。

Full GC

對(duì)整個(gè)堆進(jìn)行整理,包括Young、Tenured和Perm。Full GC因?yàn)樾枰獙?duì)整個(gè)堆進(jìn)行回收,所以比Scavenge GC要慢,因此應(yīng)該盡可能減少Full GC的次數(shù)。在對(duì)JVM調(diào)優(yōu)的過程中,很大一部分工作就是對(duì)于FullGC的調(diào)節(jié)。有如下原因可能導(dǎo)致Full GC:

1.年老代(Tenured)被寫滿

2.持久代(Perm)被寫滿

3.System.gc()被顯示調(diào)用

4.上一次GC之后Heap的各域分配策略動(dòng)態(tài)變化

Java有了GC同樣會(huì)出現(xiàn)內(nèi)存泄露問題

靜態(tài)集合類像HashMap、Vector等的使用最容易出現(xiàn)內(nèi)存泄露,這些靜態(tài)變量的生命周期和應(yīng)用程序一致,所有的對(duì)象Object也不能被釋放,因?yàn)樗麄円矊⒁恢北籚ector等應(yīng)用著。

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

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

2.各種連接,數(shù)據(jù)庫連接,網(wǎng)絡(luò)連接,IO連接等沒有顯示調(diào)用close關(guān)閉,不被GC回收導(dǎo)致內(nèi)存泄露。

3.監(jiān)聽器的使用,在釋放對(duì)象的同時(shí)沒有相應(yīng)刪除監(jiān)聽器的時(shí)候也可能導(dǎo)致內(nèi)存泄露。

以上這篇(標(biāo)題)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java OOM內(nèi)存泄漏原因及解決方法

    java OOM內(nèi)存泄漏原因及解決方法

    這篇文章主要介紹了java OOM內(nèi)存泄漏原因及解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java中Arraylist的最大長度

    Java中Arraylist的最大長度

    這篇文章主要介紹了Java中Arraylist的最大長度,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法

    spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法

    這篇文章主要介紹了關(guān)于spring的構(gòu)造函數(shù)注入屬性@ConstructorBinding用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Spring Cloud Config工作原理概述

    Spring Cloud Config工作原理概述

    Spring Cloud Config 是 Spring Cloud 生態(tài)系統(tǒng)的一部分,它提供了一種集中化管理應(yīng)用配置的方法,本文給大家介紹Spring Cloud Config工作原理概述,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • java Date獲取年月日時(shí)分秒的實(shí)現(xiàn)方法

    java Date獲取年月日時(shí)分秒的實(shí)現(xiàn)方法

    下面小編就為大家?guī)硪黄猨ava Date獲取年月日時(shí)分秒的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-06-06
  • Java中byte輸出write到文件的實(shí)現(xiàn)方法講解

    Java中byte輸出write到文件的實(shí)現(xiàn)方法講解

    今天小編就為大家分享一篇關(guān)于Java中byte輸出write到文件的實(shí)現(xiàn)方法講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Java使用ExecutorService來停止線程服務(wù)

    Java使用ExecutorService來停止線程服務(wù)

    這篇文章主要介紹了Java使用ExecutorService來停止線程服務(wù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 關(guān)于@GetMapping和@GetMapping(value=““)的區(qū)別

    關(guān)于@GetMapping和@GetMapping(value=““)的區(qū)別

    這篇文章主要介紹了關(guān)于@GetMapping和@GetMapping(value=““)的區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Spring使用@Async出現(xiàn)循環(huán)依賴原因及解決方案分析

    Spring使用@Async出現(xiàn)循環(huán)依賴原因及解決方案分析

    在Spring框架中,啟用異步功能需要在應(yīng)用主類上添加@EnableAsync注解,當(dāng)項(xiàng)目中存在循環(huán)引用時(shí),如一個(gè)異步類MessageService和一個(gè)常規(guī)類TaskService相互引用,并且這兩個(gè)類位于同一包內(nèi),這種情況下可能會(huì)觸發(fā)Spring的循環(huán)依賴異常
    2024-10-10
  • 在eclipse中使用SVN的實(shí)現(xiàn)方法(圖文教程)

    在eclipse中使用SVN的實(shí)現(xiàn)方法(圖文教程)

    這篇文章主要介紹了在eclipse中使用SVN的實(shí)現(xiàn)方法(圖文教程),文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論