亚洲精品中文字幕无乱码_久久亚洲精品无码AV大片_最新国产免费Av网址_国产精品3级片

java語言

Java內(nèi)存回收

時間:2024-07-17 12:05:59 java語言 我要投稿
  • 相關(guān)推薦

Java內(nèi)存回收

  Java的GC機(jī)制是自動進(jìn)行的,和C語言有些區(qū)別需要程序員自己保證內(nèi)存的使用和回收。下面是小編分享的具體介紹,一起來看一下吧。

  Java的內(nèi)存分配和回收也主要在Java的堆上進(jìn)行的,Java的堆中存儲了大量的對象實(shí)例,所以Java的堆也叫GC堆。

  下面主要說一下對于java堆的內(nèi)存回收 。

  什么樣的內(nèi)存可以回收

  判斷法1:引用計數(shù)

  方法:每有一個引用指向這個對象,那么這個對象的引用計數(shù)+1,反之,每有一個引用改變了指向,那么他原來指向的對象引用計數(shù)-1,當(dāng)引用計數(shù)為0的時候,這個對象也就不可能被使用了那么就可以被回收了

  問題:可能會出現(xiàn)環(huán)狀的引用,導(dǎo)致不可能被使用的對象永遠(yuǎn)不可能被回收

  示例:

  Class A {

  A a;

  Public static void main(String[] args){

  A gc1 = new A();

  A gc2 = new A();

  Gc1.a = gc2;

  Gc2.a = gc1;

  Gc1= null;

  Gc2 = null;

  }

  Gc1和gc2都被設(shè)置成null了,他們都應(yīng)該被清理,但是因?yàn)間c1的a對象指向gc2,gc2的a對象指向gc1,導(dǎo)致他們的引用計數(shù)永遠(yuǎn)為1,但是他們都永遠(yuǎn)不可能被使用了,所以這種方法存在漏洞

  判斷2:可達(dá)性分析算法

  方法:從一個叫做GC ROOTS的節(jié)點(diǎn)出發(fā),所有能夠到達(dá)的引用對象標(biāo)記起來,直到走到完全沒有引用的地方為止,這樣從這個節(jié)點(diǎn)連起來的所有的點(diǎn)(引用鏈),構(gòu)成的路線就是不可回收的,那么所有沒有被到達(dá)過的對象均可以被回收

  什么可以做GC ROOTS:虛擬機(jī)棧(棧幀中的本地變量表)中的引用的對象、方法區(qū)中類靜態(tài)屬性引用的對象、方法區(qū)中常量引用的對象、本地方法棧中JNI引用的對象

  這些對象的特點(diǎn):不可變并且隨時可能被用到,生命周期長

  補(bǔ)充:可達(dá)性分析的算法,那么沒有在引用鏈上的對象都一定會被清理嗎?不一定。當(dāng)運(yùn)行可達(dá)性分析的算法之后,會對所有沒有在引用鏈上的對象進(jìn)行一次標(biāo)記和篩選,篩選的條件為:該對象覆蓋了finallize()方法(這個方法是GC的時候如果這個對象要被回收則執(zhí)行的方法,但是在Thinking in java中不推薦用來處理收尾工作),并且這個方法沒有被執(zhí)行過,那么就會把這個對象放到一個低優(yōu)先級隊(duì)列中執(zhí)行,也就是這個對象的最后搶救的機(jī)會,如果這個時候這個對象把自己和在引用鏈上的引用連了起來,那么他在執(zhí)行完finallize方法之后,再次判斷時就不會被清理,否則會在第二次可達(dá)性判斷的時候直接清理(因?yàn)閒inallize已經(jīng)執(zhí)行過一次了),如果沒有覆蓋這個方法,那么對不起,再見

  回收算法介紹:

  回收算法1:標(biāo)記清理(Mark——sweep)算法

  標(biāo)記所有需要回收對象,然后將他們清理回收

  問題:會產(chǎn)生內(nèi)存碎片

  優(yōu)點(diǎn):不需要暫停所有線程(Stop the world)

  回收算法2:復(fù)制

  標(biāo)記后,將所有不需要回收的對象全部復(fù)制到一個空的內(nèi)存中,然后清理剛剛使用的內(nèi)存塊

  問題:浪費(fèi)資源,會有一些內(nèi)存堆無法被使用

  解決:用在新生代,新生代會有80%以上的對象經(jīng)過一次GC就會死亡,因此采用Eden + Survivor * 2的辦法,Eden = 8 * Survivor大。℉otSpot默認(rèn)),那么每次使用一個Eden + 一個Survivor,然后進(jìn)行復(fù)制清理的時候,清理Eden + Survivor中,然后將可用的對象復(fù)制到空閑的Survivor中,然后全部清空前面的使用區(qū),然后使用Eden 和復(fù)制到的Survivor

  又一個問題:如果Survivor不夠怎么辦?向老年代借空間,叫做分配擔(dān)保,不夠存放的對象會通過分配擔(dān)保進(jìn)入老年代

  問題:需要 stop the world

  回收算法3:標(biāo)記整理(Mark——compact)

  標(biāo)記后,將可用內(nèi)存向一側(cè)擺放,然后清理掉可用內(nèi)存邊緣外部的所有內(nèi)存區(qū)域

  優(yōu)點(diǎn):沒有內(nèi)存碎片的問題

  問題:需要stop the world

  回收算法4:分代收集

  將堆分代(老年代、新生代),老年代采用標(biāo)記整理、標(biāo)記清理等方法,新生代采用復(fù)制方法。

  為什么:因?yàn)槔夏甏蟛糠謱ο笫强捎玫,因此如果采用?fù)制算法,雖然沒有內(nèi)存碎片,但是空間浪費(fèi)大,而且大部分對象沒有變化,而在新生代使用復(fù)制算法,可以犧牲很小的內(nèi)存空間就獲得較好的效率

  HotSpot中內(nèi)存回收算法

  枚舉根節(jié)點(diǎn)(GC ROOTs)

  Java虛擬機(jī)采用準(zhǔn)確式GC,有一個OOPmap來標(biāo)記哪個位置有個對象,這樣在查找引用鏈的時候可以較快的找齊所有的引用鏈

  Safepoint

  在OOPmap的協(xié)助下,這個可以快速且準(zhǔn)確的完成枚舉,但是問題就是導(dǎo)致這個oopmap變化的指令非常多,如果為每一條指令生成oopmap,那么會需要大量額外空間,因此采用在特定點(diǎn)的地方生成,這些點(diǎn)同時也是safepoint的點(diǎn),那么當(dāng)需要枚舉根節(jié)點(diǎn)的時候,就讓線程運(yùn)行到這個地方再停止。

  一種方法:先停止所有線程,然后再讓沒有到安全點(diǎn)的線程自己跑到安全點(diǎn)再停下來,基本不適用,搶先試中斷

  另一種方法:主動式中斷,設(shè)置一個標(biāo)記,在執(zhí)行的時候去輪詢,而需要中斷的時候,直接將這個位置的內(nèi)存設(shè)置不可達(dá),那么線程就會進(jìn)入一個自陷異常,就自己會中斷


【Java內(nèi)存回收】相關(guān)文章:

Java的內(nèi)存模型11-28

Java編程節(jié)省內(nèi)存的方法12-16

JAVA對象創(chuàng)造及內(nèi)存布局介紹12-04

如何解決java內(nèi)存泄漏的問題03-03

查看java對象所占的內(nèi)存大小的方法12-04

Java編程節(jié)省內(nèi)存的方法有哪些11-21

Windows內(nèi)存診斷07-07

2g內(nèi)存的臺式機(jī)怎么添加內(nèi)存12-04

電腦內(nèi)存怎么清理11-30