一,java技術(shù)體系
????? *Java程序設(shè)計(jì)語言
????? * 各種硬件平臺上的Java虛擬機(jī)
?????? * Class文件格式
?????? * Java API類庫
?????? * 來自商業(yè)機(jī)構(gòu)和開源社區(qū)的第三方Java類庫
Java程序設(shè)計(jì)語言况鸣、Java虛擬機(jī)碑隆、JavaAPI類庫統(tǒng)稱為JDK(Java Development Kit), JDK是用于支持Java程序開發(fā)的最小環(huán)境。
Java API類庫中的Java SE API子集 和 Java虛擬機(jī)這兩部分統(tǒng)稱為JRE(Java Runtime Environment), JRE是支持Java程序運(yùn)行的標(biāo)準(zhǔn)環(huán)境。
按照J(rèn)ava技術(shù)關(guān)注的重點(diǎn)業(yè)務(wù)領(lǐng)域來劃分,Java技術(shù)體系可以分為四個平臺:
?????? * Java Card : 支持一些Java小程序(Applets)運(yùn)行在小內(nèi)存設(shè)備(如智能卡)上的平臺
? ? ? ? * Java ME(Micro Edition):支持Java程序運(yùn)行在移動終端(手機(jī)呐舔、PDA)上的平臺,對Java API有所精簡慷蠕,并加入了針對移動終端的支持珊拼,這個版本以前稱為J2ME.
? ? ? ? * Java SE(Standard Edition):支持面向桌面級應(yīng)用(如Windows下的應(yīng)用程序)的Java平臺,提供了完整的Java核心API,這個版本以前稱為J2SE.
? ? ? ? * Java EE(Enterprise Edition):支持使用多層架構(gòu)的企業(yè)應(yīng)用(如ERP流炕、CRM應(yīng)用)的Java平臺澎现,除了提供Java SE API外,還對其做了大量的擴(kuò)充并提供了相關(guān)的部署支持每辟,這個版本以前稱為J2EE剑辫。
注:Java EE中的擴(kuò)展一般以javax.*作為包名,而以java.*為包名的包都是Java SE API的核心包渠欺,但由于歷史原因妹蔽,一部分曾經(jīng)是擴(kuò)展包的API后來進(jìn)入了核心包,因此核心包中也包含了不少javax.*的包名挠将。
二胳岂,運(yùn)行時數(shù)據(jù)區(qū)域
??? Java虛擬機(jī)在執(zhí)行Java程序的過程中會把它所管理的內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域。 方法區(qū)(Method Area)捐名、虛擬機(jī)棧(VM Stack)旦万、本地方法棧(Native Method Stack)、堆(Heap)镶蹋、程序計(jì)數(shù)器(Program Couter Register)成艘。
1.? 程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它的作用可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器贺归。字節(jié)碼解釋器工作時就是通過改變這個計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令淆两。
??? Java虛擬機(jī)的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實(shí)現(xiàn)的。為了線程切換后能恢復(fù)到正確的執(zhí)行位置拂酣,每條線程都需要有一個獨(dú)立的程序計(jì)數(shù)器秋冰,各個線程之間的計(jì)數(shù)器互不影響,獨(dú)立存儲婶熬,我們稱這類內(nèi)存區(qū)域?yàn)椤熬€程私有”的內(nèi)存剑勾。
? ? ? 注:如果線程正在執(zhí)行的是一個Java方法,這個計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址:如果正在執(zhí)行的是Native方法赵颅,這個計(jì)數(shù)器值則為空(Undefined).
? ? ? 注:此內(nèi)存區(qū)域是唯一一個在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域虽另。
2.Java虛擬器棧(Java Virtual Machine Stacks)
???? Java虛擬機(jī)棧也是線程私有的。生命周期與線程相同饺谬,Java虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會同時創(chuàng)建一個棧幀(Stack Frame)捂刺,用于存儲局部變量表、操作棧、動態(tài)鏈接族展、方法出口等信息森缠。
? ? ? 每個方法被調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機(jī)中從入棧到出棧的過程仪缸。
? ? ? 局部變量表存放了編譯器可知的各種基本數(shù)據(jù)類型贵涵、對象引用(可能是一個指向?qū)ο笃鹗嫉刂返囊弥羔槪┖蛂eturnAddress類型(指向一條字節(jié)碼指令的地址)。
? ? ? 局部變量表所需的內(nèi)存空間在編譯期間完成分配腹殿,當(dāng)進(jìn)入一個方法時独悴,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運(yùn)行期間不會改變局部變量表的大小锣尉。
? ? ? Java虛擬器規(guī)范中刻炒,對這個區(qū)域規(guī)定了兩種異常狀況:如果線程請求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常自沧;如果虛擬機(jī)椃匕拢可以自動擴(kuò)展,當(dāng)擴(kuò)展時無法申請到足夠的內(nèi)存時會拋出OutOfMemoryError異常拇厢。
3.本地方法棧(Native Method Stacks)
? ? ? 本地方法棧與虛擬機(jī)棧所發(fā)揮的作用非常類似爱谁。區(qū)別在于虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧是為虛擬機(jī)使用到的Native方法服務(wù)的孝偎。
? ? ? 本地方法棧也會拋出StackOverflowError和OutOfMemoryError異常
4.Java堆
? ? ? Java堆(Java Heap)是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊访敌。是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動時創(chuàng)建衣盾。此內(nèi)存區(qū)域的唯一目的就是存放對象實(shí)例寺旺。
? ? ? Java虛擬機(jī)規(guī)范規(guī)定:所有的對象實(shí)例以及數(shù)組都要在堆上分配。
? ? ? Java堆是垃圾收集器管理的主要區(qū)域势决,因此很多時候也被稱為“GC堆”(Garbage Collected Heap).
? ? ? Java虛擬機(jī)規(guī)范規(guī)定阻塑,Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上連續(xù)即可果复。
? ? ? 當(dāng)前駐留的虛擬機(jī)都是按照可擴(kuò)展來實(shí)現(xiàn)的(通過-Xmx 和 -Xms控制)陈莽。如果在堆中沒有內(nèi)存完成實(shí)例分配,并且堆也無法再擴(kuò)展時虽抄,將會拋出OutOfMemoryError異常走搁。
5.方法區(qū)
? ? ? 方法區(qū)(Method Area)與Java堆一樣,是各個線程共享的內(nèi)存區(qū)域迈窟,它用于存儲已被虛擬機(jī)加載的類信息朱盐、常量、靜態(tài)變量菠隆、即時編譯器編譯后的代碼等數(shù)據(jù)。
? ? Java虛擬機(jī)規(guī)范規(guī)定,當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時骇径,將拋出OutOfMemoryError異常躯肌。
6.運(yùn)行時常量池
? ? ? 運(yùn)行時常量池(Runtime Constant Pool)是方法區(qū)的一部分。Class文件中除了有類的版本破衔、字段清女、方法、接口等描述信息外晰筛,還有一項(xiàng)信息是常量池(Constant Pool Table)嫡丙,用于存放編譯期生成的各種字面量和符號引用。這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時常量池中读第。
? ? ? 運(yùn)行時常量池相對于Class文件常量池的另外一個重要特征是具備動態(tài)性曙博,不僅Class文件中的常量池的內(nèi)容可以進(jìn)入方法區(qū)運(yùn)行時常量池,運(yùn)行期間也可能將新的常量放入池中怜瞒。
7.直接內(nèi)存
直接內(nèi)存(Direct Memory)并不是虛擬機(jī)運(yùn)行時數(shù)據(jù)區(qū)的一部分父泳,也不是Java虛擬機(jī)規(guī)范匯總定義的內(nèi)存區(qū)域,例如, JDK1.4引入的NIO類吴汪,引入了基于通道(Channel)與緩沖區(qū)(Buffer)的I/O方式惠窄,它可以使用Native函數(shù)庫直接分配堆外內(nèi)存,然后通過一個存儲在Java堆里面的DirectByteBuffer對象作為這塊內(nèi)存的引用進(jìn)行操作漾橙。
? ? ? 注意:直接內(nèi)存雖然不包含在堆內(nèi)存中杆融,但是它也是一塊需要的內(nèi)存區(qū)域,因此霜运,在計(jì)算各個內(nèi)存區(qū)域總和的時候要計(jì)算在內(nèi)脾歇。
三、對象訪問
對于Object obj = new Object();
"Object obj"這部分的語義將會反映到Java棧的本地變量表中觉渴,作為一個reference類型數(shù)據(jù)出現(xiàn)介劫。
new Object()”這部分語義將會反映到Java堆中,形成一塊存儲了Object類型所有實(shí)例數(shù)據(jù)值的結(jié)構(gòu)化內(nèi)存案淋。
由于reference類型在Java虛擬機(jī)規(guī)范里面只規(guī)定了一個指向?qū)ο蟮囊米希虼瞬煌奶摂M機(jī)實(shí)現(xiàn)會有不同的實(shí)現(xiàn)對象訪問的方式,主流的訪問方式有兩種:使用句柄 和直接指針踢京。
3.1使用句柄
使用該方式誉碴,Java堆中將會劃分出一塊內(nèi)存來作為句柄池,reference中存儲的就是對象的句柄地址瓣距,而句柄中存對象實(shí)例數(shù)據(jù)和類型數(shù)據(jù)的具體地址信息黔帕。如上圖2。
3.2使用指針
reference中直接存儲的就是對象地址蹈丸;
句柄訪問方式最大的好處是reference中存儲的是穩(wěn)定的句柄地址成黄,在對象被移動時只會改變句柄中的實(shí)例數(shù)據(jù)指針呐芥,而reference本身不需要被修改。
直接指針訪問方式的最大好處就是速度更快奋岁,它節(jié)省了一次指針定位的時間開銷思瘟。Sun HotSpot虛擬機(jī)是使用第二種方式的。
4.實(shí)戰(zhàn):OutOfMemoryError異常
1闻伶、Java堆的溢出
??? 通過指定VM Args參數(shù)滨攻,可以設(shè)置虛擬機(jī)的啟動參數(shù)。-Xms參數(shù)指定堆的最小值蓝翰, -Xmx參數(shù)指定堆的最大值光绕,通過參數(shù)-XX:+HeapDumpOnOutOfMemoryError可以讓虛擬機(jī)在出現(xiàn)內(nèi)存溢出異常時Dump出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲文件以便后續(xù)分析。
??? 例如畜份,在VM Arg參數(shù)中指定:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError
可以將堆的大小設(shè)置為20M(將堆的最小值-Xms參數(shù)與最大值-Xmx參數(shù)設(shè)置為一樣即可避免堆自動擴(kuò)展)诞帐,并導(dǎo)出Dump文件
如下程序:
2.虛擬機(jī)棧和本地方法棧溢出
VM Arg中 -Xoss參數(shù)可以設(shè)置本地方法棧大小(由于HotSpot虛擬機(jī)中并不區(qū)分虛擬機(jī)棧和本地方法棧漂坏,因此-Xoss參數(shù)是無效的)景埃,-Xss參數(shù)指定虛擬機(jī)棧的大小
關(guān)于虛擬機(jī)棧和本地方法棧,有兩種可能的異常:StackOverflowError和OutOfMemoryError異常顶别。
實(shí)驗(yàn)表明:在單個線程下谷徙,無論是由于棧幀太大,還是虛擬機(jī)棧容量太小驯绎,當(dāng)內(nèi)存無法分配時完慧,虛擬機(jī)都會拋出StackOverflowError異常,不會拋出OutOfMemoryError異常剩失。
注意:如果是建立過多線程導(dǎo)致的內(nèi)存溢出屈尼,在不能減少線程數(shù)或者更換64位虛擬機(jī)的情況下,就只能通過減少最大堆和減少棧容量來換取更多的線程拴孤。
3.運(yùn)行時常量池溢出(運(yùn)行時常量池屬于方法區(qū)方法區(qū)溢出)
常量池分配在方法區(qū)脾歧。通過-XX:PermSize和-XX:MaxPermSize可以限制方法區(qū)的大小,從而間接限制其中常量池的容量演熟。
4.方法區(qū)溢出
方法區(qū)用于存放Class的相關(guān)信息鞭执,如類名、訪問修飾符芒粹、常量池兄纺、字段描述、方法描述等化漆。對這個區(qū)域的測試估脆,基本思路是運(yùn)行時產(chǎn)生大量的類去填滿方法區(qū),直到溢出座云。
CGLib (Code Generation Library) 是一個強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫疙赠。它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口付材。Hibernate用它來實(shí)現(xiàn)PO字節(jié)碼的動態(tài)生成。CGLib 比 Java 的 java.lang.reflect.Proxy 類更強(qiáng)的在于它不僅可以接管接口類的方法棺聊,還可以接管普通類的方法伞租。
CGLib 的底層是Java字節(jié)碼操作框架 —— ASM。
當(dāng)前的很多主流框架限佩,如Spring和Hibernate對類進(jìn)行增強(qiáng)時,都會使用到CGLib這類字節(jié)碼技術(shù)裸弦,增強(qiáng)的類越多祟同,就需要越大的方法區(qū)來保證動態(tài)生成的Class可以加載如內(nèi)存。
5.本地直接內(nèi)存溢出
DirectMemory容量可通過-XX:MaxDirectMemorySize指定理疙,如果不指定晕城,則默認(rèn)與Java堆的最大值(-Xmx指定)一樣
五、垃圾回收器
垃圾收集(Garbage Collection, GC)窖贤,可以回收堆上的對象砖顷,還可以回收方法區(qū)的“廢棄常量”和“無用的類”。
1赃梧、判斷對象是否存活
GC在對堆進(jìn)行回收之前滤蝠,第一件事就是確定哪些對象可以回收。
方案一:引用計(jì)數(shù)算法(Reference Counting)
過程是:給對象中添加一個引用計(jì)數(shù)器授嘀,每當(dāng)有一個地方引用它時物咳,計(jì)數(shù)器值就加1;當(dāng)引用失效時蹄皱,計(jì)數(shù)器值就減1览闰;任何時刻計(jì)數(shù)器都為0的對象就是不可能再被使用的,可以回收巷折。
引用計(jì)數(shù)方案最大的問題是:很難解決對象之間的相互循環(huán)引用的問題压鉴。當(dāng)兩個對象沒有其他對象引用,只是它們之間相互引用對方锻拘,此時這兩個對象已經(jīng)不能再被訪問油吭,但是引用計(jì)數(shù)都不為0;
方案二:根搜索算法(GC Roots Tracing)
思路是:通過一系列的名為“GC Roots”的對象作為起始點(diǎn)逊拍,從這些節(jié)點(diǎn)開始向下搜素上鞠,搜索所走過的路徑稱為引用鏈(Reference Chain),當(dāng)一個對象到GC Roots沒有任何引用鏈相連(用圖論的話來說就是從GC Roots到這個對象不可達(dá))時,則證明此對象是不可用的芯丧。
在Java語言里芍阎,可作為GC Roots的對象包括以下幾種:
?????? ** 虛擬機(jī)棧(棧幀中的本地變量表)中的引用的對象
?????? ** 方法區(qū)中的類靜態(tài)屬性引用的對象
?????? ** 方法區(qū)中的常量引用的對象。
?????? ** 本地方法棧中JNI(即一般說的Native方法)的引用的對象缨恒。
2谴咸、引用
在JDK 1.2之前轮听, Java中引用的定義時:如果reference類型的數(shù)據(jù)中存儲的數(shù)值代表的是另外一塊內(nèi)存的起始地址,就稱這塊內(nèi)存代表著一個引用岭佳。
在JDK1.2之后血巍,Java對引用的概念進(jìn)行了擴(kuò)充,將引用分為強(qiáng)引用(Strong Reference)珊随、軟引用(Soft Reference)述寡、弱引用(Weak Reference)、虛引用(Phantom Reference)四種叶洞。這四種引用強(qiáng)度依次逐漸減弱鲫凶。
????? ** 強(qiáng)引用,就是指在程序代碼之中普遍存在的衩辟,類似“Object obj = new Object()”這類的引用螟炫,只要強(qiáng)引用存在,垃圾回收器永遠(yuǎn)不會回收掉被引用的對象艺晴。
? ? ? ? ** 軟引用昼钻, 是指一些有用,但并非必需的對象封寞,對于軟引用關(guān)聯(lián)著的對象然评,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會把這些對象列進(jìn)回收范圍之中并進(jìn)行第二次回收钥星。如果這次回收還是沒有足夠的內(nèi)存沾瓦,才會拋出內(nèi)存溢出異常。
? ? ? ? ** 弱引用谦炒,被弱引用關(guān)聯(lián)的對象只能生存到下一次垃圾收集發(fā)生之前贯莺。當(dāng)垃圾收集器工作時,無論當(dāng)前內(nèi)存是否足夠宁改,都會回收掉只被弱引用關(guān)聯(lián)的對象缕探。
? ? ? ? ** 虛引用,一個對象是否有虛引用的存在还蹲,完全不會對其生存時間構(gòu)成影響爹耗,也無法通過虛引用來取得一個對象實(shí)例。為一個對象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是希望能在這個對象被收集器回收時收到一個系統(tǒng)通知谜喊。
3潭兽、關(guān)于對象的死亡的二次標(biāo)記
要真正宣告一個對象死亡,至少要經(jīng)歷兩次標(biāo)記過程:如果對象在進(jìn)行根搜索后發(fā)現(xiàn)是不可達(dá)的斗遏,那么它將會被第一次標(biāo)記并且進(jìn)行一次篩選山卦,篩選的條件是此對象是否有必要執(zhí)行finalize()方法。當(dāng)對象沒有覆蓋finalize()方法或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過诵次,這兩種情況將被視為“沒有必要執(zhí)行finalize()”账蓉。
如果一個對象被判定為有必要執(zhí)行finalize()方法枚碗,那么這個對象將會被放置在一個名為F-Queue的隊(duì)列中,并在稍后由一條由虛擬機(jī)自動建立的铸本、低優(yōu)先級的Finalizer線程去執(zhí)行調(diào)用finalize()肮雨,稍后GC將對F-Queue中的對象進(jìn)行第二次小規(guī)模的標(biāo)記,如果對象在finalize()中又重新關(guān)聯(lián)到了GC Roots對象箱玷,那么第二次標(biāo)記時它將被移除出“即將回收”的集合怨规,否則,對象將被回收锡足。
任何一個對象的finalize()方法都只會被系統(tǒng)自動調(diào)用一次椅亚,第二次面臨回收時,它的finalize()方法不會再被調(diào)用舱污。
4、回收方法區(qū)
? ? Java虛擬機(jī)規(guī)范中并沒有要求必須在方法區(qū)實(shí)現(xiàn)垃圾回收弥虐,在方法區(qū)進(jìn)行垃圾收集的“性價比”一般比較低:在堆中扩灯,常規(guī)應(yīng)用進(jìn)行一次垃圾回收一般可以回收70%~80%的空間,而代碼區(qū)(永久代)的垃圾回收效率遠(yuǎn)低于此霜瘪。
代碼區(qū)回收的內(nèi)容有:廢棄常量和無用的類珠插。
回收廢棄常量的方法與回收堆中的對象非常類似,常量池中的其他類(接口)颖对、方法捻撑、字段的符號引用也與此類似。
回收“無用的類”的條件是:同時滿足以下3個條件的類才算是“無用的類”:
????? ** 該類所有的實(shí)例都已經(jīng)被回收缤底,也就是Java堆中不存在該類的任何實(shí)例
???? ? **?加載該類的ClassLoader已經(jīng)被回收顾患。
??? ?? **?該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法个唧。
注:是否對類進(jìn)行回收江解,HotSpot虛擬機(jī)提供了-Xnoclassgc參數(shù)進(jìn)行控制,還可以使用-verbose:class及-XX:+TraceClassLoading徙歼、-XX:+TraceClassUnLoading查看類的加載和卸載信息犁河。
六、垃圾回收算法
1魄梯、標(biāo)記-清除算法
“標(biāo)記-清除”算法是最基礎(chǔ)的垃圾回收算法桨螺,之所以說它是最基礎(chǔ)的收集算法,是因?yàn)楹罄m(xù)的收集算法都是基于這種思路并對其缺點(diǎn)進(jìn)行改進(jìn)得到的酿秸。
該算法分為兩個階段:“標(biāo)記”和“清除”灭翔,首先標(biāo)記出所有需要回收的對象,然后在標(biāo)記完成后統(tǒng)一回收掉所有被標(biāo)記的對象允扇。
主要缺點(diǎn)有兩個: 一個是效率問題缠局,標(biāo)記和清除過程的效率都不高则奥;另外一個是空間問題,標(biāo)記清除之后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會導(dǎo)致狭园,當(dāng)程序在以后的運(yùn)行過程中需要分配較大對象時無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另外一次垃圾回收動作读处。
2.復(fù)制算法
為了解決效率問題,出現(xiàn)了“復(fù)制”的收集算法唱矛。
思路是:將可用內(nèi)存按容量劃分為大小相等的兩塊罚舱,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了绎谦,就將還存活著的對象復(fù)制到另外一塊上面管闷,然后再把已使用過的內(nèi)存空間一次清理掉。
優(yōu)點(diǎn)是:內(nèi)存分配時不用考慮內(nèi)存碎片等復(fù)雜情況窃肠,實(shí)現(xiàn)簡單包个,運(yùn)行高效
缺點(diǎn)是:可利用的內(nèi)存空間縮小為原來的一半,內(nèi)存利用率低冤留。
3.標(biāo)記-整理算法(Mark-Compact)
復(fù)制收集算法在對象存活率較高時就要執(zhí)行較多的復(fù)制操作碧囊,效率將會變低。更關(guān)鍵的是纤怒,如果不想浪費(fèi)50%的空間糯而,就需要有額外的空間進(jìn)行分配擔(dān)保。
算法思路:標(biāo)記過程仍然與“標(biāo)記-清除”算法一樣泊窘,但后續(xù)步驟不是直接對可回收對象進(jìn)行清理熄驼,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存烘豹。
4.分代收集算法(Generational Collection)
該算法只是根據(jù)對象存活周期的不同將內(nèi)存劃分為幾塊瓜贾。一般是把Java堆分為新生代和老年代,這樣就可以根據(jù)各個年代的特點(diǎn)采用最適合的收集算法吴叶。新生代中阐虚,每次來及收集時都發(fā)現(xiàn)有大批對象死去,只有少量存活蚌卤,就選用復(fù)制算法实束。而老年代中因?yàn)閷ο蟠婊盥矢摺]有額外空間對它進(jìn)行分配擔(dān)保逊彭,就必須使用“標(biāo)記-清理”或“標(biāo)記-整理”算法來回收咸灿。
內(nèi)存回收與垃圾收集器在很多時候都是影響系統(tǒng)性能、并發(fā)能力的主要因素之一侮叮,虛擬機(jī)之所以提供多種不同的收集器及大量的調(diào)節(jié)參數(shù)避矢,是因?yàn)橹挥懈鶕?jù)實(shí)際應(yīng)用需求、實(shí)現(xiàn)方式選擇最優(yōu)的收集方式才能獲取最好的性能。