成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

優(yōu)秀的Java程序員必須了解的GC哪些

開(kāi)發(fā) 后端
本篇文章首先簡(jiǎn)單介紹GC的工作原理之后,然后再對(duì)GC的幾個(gè)關(guān)鍵問(wèn)題進(jìn)行深入探討,最后提出一些Java程序設(shè)計(jì)建議,從GC角度提高Java程序的性能。

[[383298]]

 一個(gè)優(yōu)秀的Java程序員必須了解GC的工作原理、如何優(yōu)化GC的性能、如何與GC進(jìn)行有限的交互,因?yàn)橛幸恍?yīng)用程序?qū)π阅芤筝^高,例如嵌入式系統(tǒng)、實(shí)時(shí)系統(tǒng)等,只有全面提升內(nèi)存的管理效率 ,才能提高整個(gè)應(yīng)用程序的性能。

一個(gè)優(yōu)秀的Java程序員必須了解GC的工作原理、如何優(yōu)化GC的性能、如何與GC進(jìn)行有限的交互,因?yàn)橛幸恍?yīng)用程序?qū)π阅芤筝^高,例如嵌入式系統(tǒng)、實(shí)時(shí)系統(tǒng)等,只有全面提升內(nèi)存的管理效率 ,才能提高整個(gè)應(yīng)用程序的性能。本篇文章首先簡(jiǎn)單介紹GC的工作原理之后,然后再對(duì)GC的幾個(gè)關(guān)鍵問(wèn)題進(jìn)行深入探討,最后提出一些Java程序設(shè)計(jì)建議,從GC角度提高Java程序的性能。

GC的基本原理

Java的內(nèi)存管理實(shí)際上就是對(duì)象的管理,其中包括對(duì)象的分配和釋放。

對(duì)于程序員來(lái)說(shuō),分配對(duì)象使用new關(guān)鍵字;釋放對(duì)象時(shí),只要將對(duì)象所有引用賦值為null,讓程序不能夠再訪問(wèn)到這個(gè)對(duì)象,我們稱該對(duì)象為"不可達(dá)的".GC將負(fù)責(zé)回收所有"不可達(dá)"對(duì)象的內(nèi)存空間。

對(duì)于GC來(lái)說(shuō),當(dāng)程序員創(chuàng)建對(duì)象時(shí),GC就開(kāi)始監(jiān)控這個(gè)對(duì)象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對(duì)象。通過(guò)這種方式確定哪些對(duì)象是"可達(dá)的",哪些對(duì)象是"不可達(dá)的".當(dāng)GC確定一些對(duì)象為"不可達(dá)"時(shí),GC就有責(zé)任回收這些內(nèi)存空間。

但是,為了保證GC能夠在不同平臺(tái)實(shí)現(xiàn)的問(wèn)題,Java規(guī)范對(duì)GC的很多行為都沒(méi)有進(jìn)行嚴(yán)格的規(guī)定。例如,對(duì)于采用什么類型的回收算法、什么時(shí)候進(jìn)行回收等重要問(wèn)題都沒(méi)有明確的規(guī)定。因此,不同的JVM的實(shí)現(xiàn)者往往有不同的實(shí)現(xiàn)算法。這也給Java程序員的開(kāi)發(fā)帶來(lái)行多不確定性。本文研究了幾個(gè)與GC工作相關(guān)的問(wèn)題,努力減少這種不確定性給Java程序帶來(lái)的負(fù)面影響。

增量式GC( Incremental GC )

GC在JVM中通常是由一個(gè)或一組進(jìn)程來(lái)實(shí)現(xiàn)的,它本身也和用戶程序一樣占用heap空間,運(yùn)行時(shí)也占用CPU.當(dāng)GC進(jìn)程運(yùn)行時(shí),應(yīng)用程序停止運(yùn)行。因此,當(dāng)GC運(yùn)行時(shí)間較長(zhǎng)時(shí),用戶能夠感到 Java程序的停頓,另外一方面,如果GC運(yùn)行時(shí)間太短,則可能對(duì)象回收率太低,這意味著還有很多應(yīng)該回收的對(duì)象沒(méi)有被回收,仍然占用大量?jī)?nèi)存。

因此,在設(shè)計(jì)GC的時(shí)候,就必須在停頓時(shí)間和回收率之間進(jìn)行權(quán)衡。一個(gè)好的GC實(shí)現(xiàn)允許用戶定義自己所需要的設(shè)置,例如有些內(nèi)存有限有設(shè)備,對(duì)內(nèi)存的使用量非常敏感,希望GC能夠準(zhǔn)確的回收內(nèi)存,它并不在意程序速度的放慢。

另外一些實(shí)時(shí)網(wǎng)絡(luò)游戲,就不能夠允許程序有長(zhǎng)時(shí)間的中斷。增量式GC就是通過(guò)一定的回收算法,把一個(gè)長(zhǎng)時(shí)間的中斷,劃分為很多個(gè)小的中斷,通過(guò)這種方式減少GC對(duì)用戶程序的影響。雖然,增量式GC在整體性能上可能不如普通GC的效率高,但是它能夠減少程序的最長(zhǎng)停頓時(shí)間。

Sun JDK提供的HotSpot JVM就能支持增量式GC.HotSpot JVM缺省GC方式為不使用增量GC,為了啟動(dòng)增量GC,我們必須在運(yùn)行Java程序時(shí)增加-Xincgc的參數(shù)。

HotSpot JVM增量式GC的實(shí)現(xiàn)是采用Train GC算法。它的基本想法就是,將堆中的所有對(duì)象按照創(chuàng)建和使用情況進(jìn)行分組(分層),將使用頻繁高和具有相關(guān)性的對(duì)象放在一隊(duì)中,隨著程序的運(yùn)行,不斷對(duì)組進(jìn)行調(diào)整。當(dāng)GC運(yùn)行時(shí),它總是先回收最老的(最近很少訪問(wèn)的)的對(duì)象,如果整組都為可回收對(duì)象,GC將整組回收。這樣,每次GC運(yùn)行只回收一定比例的不可達(dá)對(duì)象,保證程序的順暢運(yùn)行。

詳解finalize函數(shù)

finalize是位于Object類的一個(gè)方法,該方法的訪問(wèn)修飾符為protected,由于所有類為Object的子類,因此用戶類很容易訪問(wèn)到這個(gè)方法。由于,finalize函數(shù)沒(méi)有自動(dòng)實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,我們必須手動(dòng)的實(shí)現(xiàn),因此finalize函數(shù)的最后一個(gè)語(yǔ)句通常是super.finalize()。通過(guò)這種方式,我們可以實(shí)現(xiàn)從下到上實(shí)現(xiàn)finalize的調(diào)用,即先釋放自己的資源,然后再釋放父類的資源。

根據(jù)Java語(yǔ)言規(guī)范,JVM保證調(diào)用finalize函數(shù)之前,這個(gè)對(duì)象是不可達(dá)的,但是JVM不保證這個(gè)函數(shù)一定會(huì)被調(diào)用。另外,規(guī)范還保證finalize函數(shù)最多運(yùn)行一次。

很多Java初學(xué)者會(huì)認(rèn)為這個(gè)方法類似與C++中的析構(gòu)函數(shù),將很多對(duì)象、資源的釋放都放在這一函數(shù)里面。其實(shí),這不是一種很好的方式。原因有三,其一,GC為了能夠支持finalize函數(shù),要對(duì)覆蓋這個(gè)函數(shù)的對(duì)象作很多附加的工作。其二,在finalize運(yùn)行完成之后,該對(duì)象可能變成可達(dá)的,GC還要再檢查一次該對(duì)象是否是可達(dá)的。因此,使用 finalize會(huì)降低GC的運(yùn)行性能。其三,由于GC調(diào)用finalize的時(shí)間是不確定的,因此通過(guò)這種方式釋放資源也是不確定的。

通常,finalize用于一些不容易控制、并且非常重要資源的釋放,例如一些I/O的操作,數(shù)據(jù)的連接。這些資源的釋放對(duì)整個(gè)應(yīng)用程序是非常關(guān)鍵的。在這種情況下,程序員應(yīng)該以通過(guò)程序本身管理(包括釋放)這些資源為主,以finalize函數(shù)釋放資源方式為輔,形成一種雙保險(xiǎn)的管理機(jī)制,而不應(yīng)該僅僅依靠finalize來(lái)釋放資源。

下面給出一個(gè)例子說(shuō)明,finalize函數(shù)被調(diào)用以后,仍然可能是可達(dá)的,同時(shí)也可說(shuō)明一個(gè)對(duì)象的finalize只可能運(yùn)行一次。 

  1.  1 class MyObject{  
  2.  2   
  3.  3 Test main; //記錄Test對(duì)象,在finalize中時(shí)用于恢復(fù)可達(dá)性  
  4.  4   
  5.  5 public MyObject(Test t)  
  6.  6   
  7.  7 {  
  8.  8  
  9.  9 main=t; //保存Test 對(duì)象  
  10. 10   
  11. 11 }  
  12. 12   
  13. 13 protected void finalize()  
  14. 14   
  15. 15 {  
  16. 16   
  17. 17 main.ref=this;// 恢復(fù)本對(duì)象,讓本對(duì)象可達(dá)  
  18. 18   
  19. 19 System.out.println("This is finalize");//用于測(cè)試finalize只運(yùn)行一次  
  20. 20   
  21. 21 }  
  22. 22   
  23. 23 }  
  24. 24   
  25. 25 class Test {  
  26. 26   
  27. 27 MyObject ref;  
  28. 28   
  29. 29 public static void main(String[] args) {  
  30. 30   
  31. 31 Test test=new Test();  
  32. 32   
  33. 33 test.ref=new MyObject(test);  
  34. 34   
  35. 35 test.ref=null; //MyObject對(duì)象為不可達(dá)對(duì)象,finalize將被調(diào)用  
  36. 36   
  37. 37 System.gc();  
  38. 38   
  39. 39 if (test.ref!=null) System.out.println("My Object還活著");  
  40. 40   
  41. 41 }  
  42. 42   
  43. 43 }  
  44. 44   
  45. 45 運(yùn)行結(jié)果:  
  46. 46   
  47. 47 This is finalize  
  48. 48   
  49. 49 MyObject還活著 

此例子中,需要注意的是雖然MyObject對(duì)象在finalize中變成可達(dá)對(duì)象,但是下次回收時(shí)候,finalize卻不再被調(diào)用,因?yàn)閒inalize函數(shù)最多只調(diào)用一次。

程序如何與GC進(jìn)行交互

Java2增強(qiáng)了內(nèi)存管理功能,增加了一個(gè)java.lang.ref包,其中定義了三種引用類。這三種引用類分別為SoftReference、WeakReference和 PhantomReference.通過(guò)使用這些引用類,程序員可以在一定程度與GC進(jìn)行交互,以便改善GC的工作效率。這些引用類的引用強(qiáng)度介于可達(dá)對(duì)象和不可達(dá)對(duì)象之間。

創(chuàng)建一個(gè)引用對(duì)象也非常容易,例如如果你需要?jiǎng)?chuàng)建一個(gè)Soft Reference對(duì)象,那么首先創(chuàng)建一個(gè)對(duì)象,并采用普通引用方式(可達(dá)對(duì)象);然后再創(chuàng)建一個(gè)SoftReference引用該對(duì)象;最后將普通引用設(shè)置為null.通過(guò)這種方式,這個(gè)對(duì)象就只有一個(gè)Soft Reference引用。同時(shí),我們稱這個(gè)對(duì)象為Soft Reference 對(duì)象。

Soft Reference的主要特點(diǎn)是據(jù)有較強(qiáng)的引用功能。只有當(dāng)內(nèi)存不夠的時(shí)候,才進(jìn)行回收這類內(nèi)存,因此在內(nèi)存足夠的時(shí)候,它們通常不被回收。另外,這些引用對(duì)象還能保證在Java拋出OutOfMemory 異常之前,被設(shè)置為null.它可以用于實(shí)現(xiàn)一些常用圖片的緩存,實(shí)現(xiàn)Cache的功能,保證最大限度的使用內(nèi)存而不引起OutOfMemory.以下給出這種引用類型的使用偽代碼; 

  1.  1 //申請(qǐng)一個(gè)圖像對(duì)象  
  2.  2   
  3.  3 Image image=new Image();//創(chuàng)建Image對(duì)象  
  4.  4   
  5.  5 …  
  6.  6   
  7.  7 //使用 image  
  8.  8   
  9.  9 …  
  10. 10   
  11. 11 //使用完了image,將它設(shè)置為soft 引用類型,并且釋放強(qiáng)引用;  
  12. 12  
  13. 13 SoftReference sr=new SoftReference(image);  
  14. 14   
  15. 15 image=null 
  16. 16   
  17. 17 …  
  18. 18   
  19. 19 //下次使用時(shí)  
  20. 20   
  21. 21 if (sr!=null) image=sr.get();  
  22. 22   
  23. 23 else{  
  24. 24   
  25. 25 //由于GC由于低內(nèi)存,已釋放image,因此需要重新裝載; 
  26. 26   
  27. 27 image=new Image();  
  28. 28   
  29. 29 sr=new SoftReference(image);  
  30. 30   
  31. 31 } 

Weak引用對(duì)象與Soft引用對(duì)象的最大不同就在于:GC在進(jìn)行回收時(shí),需要通過(guò)算法檢查是否回收Soft引用對(duì)象,而對(duì)于Weak引用對(duì)象,GC總是進(jìn)行回收。Weak引用對(duì)象更容易、更快被 GC回收。雖然,GC在運(yùn)行時(shí)一定回收Weak對(duì)象,但是復(fù)雜關(guān)系的Weak對(duì)象群常常需要好幾次GC的運(yùn)行才能完成。Weak引用對(duì)象常常用于Map結(jié)構(gòu)中,引用數(shù)據(jù)量較大的對(duì)象,一旦該對(duì)象的強(qiáng)引用為null時(shí),GC能夠快速地回收該對(duì)象空間。

Phantom引用的用途較少,主要用于輔助 finalize函數(shù)的使用。Phantom對(duì)象指一些對(duì)象,它們執(zhí)行完了finalize函數(shù),并為不可達(dá)對(duì)象,但是它們還沒(méi)有被GC回收。這種對(duì)象可以輔助finalize進(jìn)行一些后期的回收工作,我們通過(guò)覆蓋Reference的clear()方法,增強(qiáng)資源回收機(jī)制的靈活性。

一些Java編碼的建議

根據(jù)GC的工作原理,我們可以通過(guò)一些技巧和方式,讓GC運(yùn)行更加有效率,更加符合應(yīng)用程序的要求。以下就是一些程序設(shè)計(jì)的幾點(diǎn)建議。

1.最基本的建議就是盡早釋放無(wú)用對(duì)象的引用。大多數(shù)程序員在使用臨時(shí)變量的時(shí)候,都是讓引用變量在退出活動(dòng)域(scope)后,自動(dòng)設(shè)置為null.我們?cè)谑褂眠@種方式時(shí)候,必須特別注意一些復(fù)雜的對(duì)象圖,例如數(shù)組,隊(duì)列,樹(shù),圖等,這些對(duì)象之間有相互引用關(guān)系較為復(fù)雜。對(duì)于這類對(duì)象,GC回收它們一般效率較低。如果程序允許,盡早將不用的引用對(duì)象賦為null.這樣可以加速GC的工作。

2.盡量少用finalize函數(shù)。finalize函數(shù)是Java提供給程序員一個(gè)釋放對(duì)象或資源的機(jī)會(huì)。但是,它會(huì)加大GC的工作量,因此盡量少采用finalize方式回收資源。

3.如果需要使用經(jīng)常使用的圖片,可以使用soft應(yīng)用類型。它可以盡可能將圖片保存在內(nèi)存中,供程序調(diào)用,而不引起OutOfMemory.

4.注意集合數(shù)據(jù)類型,包括數(shù)組,樹(shù),圖,鏈表等數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)對(duì)GC來(lái)說(shuō),回收更為復(fù)雜。另外,注意一些全局的變量,以及一些靜態(tài)變量。這些變量往往容易引起懸掛對(duì)象(dangling reference),造成內(nèi)存浪費(fèi)。

5.當(dāng)程序有一定的等待時(shí)間,程序員可以手動(dòng)執(zhí)行System.gc(),通知GC運(yùn)行,但是Java語(yǔ)言規(guī)范并不保證GC一定會(huì)執(zhí)行。使用增量式GC可以縮短Java程序的暫停時(shí)間。 

 

責(zé)任編輯:龐桂玉 來(lái)源: JAVA高級(jí)架構(gòu)
相關(guān)推薦

2009-06-15 10:43:45

Java程序員Java程序GC

2017-11-14 21:30:15

2024-03-20 17:35:42

2009-07-03 16:07:58

2015-10-12 08:56:37

程序員成長(zhǎng)法則

2020-03-29 08:19:56

程序員代碼

2021-05-29 07:32:14

優(yōu)秀程序員代碼

2012-05-25 10:54:24

程序員

2015-06-17 14:24:48

優(yōu)秀程序員整潔代碼

2018-08-13 13:56:24

2020-03-09 11:14:25

程序員技術(shù)設(shè)計(jì)

2014-08-29 11:09:44

程序員

2018-07-02 10:15:11

Java程序員注解

2013-07-09 15:26:29

程序員算法

2015-03-24 14:11:41

程序員

2015-08-03 09:09:20

程序員腦子快

2016-12-19 17:35:58

程序員特質(zhì)

2009-01-08 09:04:18

2015-06-24 10:33:17

程序員擅長(zhǎng)數(shù)學(xué)

2012-11-09 13:44:48

ScalaJVMJava
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 99在线免费观看 | 国产成人午夜电影网 | 九色av | 四虎在线播放 | 中文字幕一区在线观看视频 | 二区在线视频 | 中文字幕一区二区三区日韩精品 | 国产欧美日韩一区二区三区 | 99久久精品免费看国产四区 | 日韩在线视频一区 | 一区二区三区四区视频 | 日韩欧美中文 | 狠狠的操 | 久久这里只有精品首页 | 免费麻豆视频 | 色综合99| 午夜成人免费电影 | 一区二区三区免费 | 国产精品久久久久久中文字 | 91国内精精品久久久久久婷婷 | 99久久免费精品国产免费高清 | 国产成人91视频 | 先锋av资源网 | 国产成人精品视频在线观看 | 亚洲成网站 | 在线免费观看色 | 国产高清无av久久 | 国产成人精品一区二区三区视频 | 国产精品久久久久久久免费大片 | 一级免费毛片 | 91在线电影| 亚洲久草视频 | 成人影院在线观看 | 日韩一区二区三区精品 | 午夜精品一区二区三区在线视 | 在线中文字幕av | 丝袜美腿一区二区三区动态图 | 国产成人jvid在线播放 | 精品久久久久久久 | 农夫在线精品视频免费观看 | 台湾a级理论片在线观看 |