欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
內存泄漏,走開(kāi)
內存泄漏,走開(kāi)!
By: Staffan Larsen
Translate: glorywine
抽象
盡管java虛擬機和垃圾回收機制管理著(zhù)大部分的內存事務(wù),但是在java軟件中還是可能存在內存泄漏的情況。的確,在大型工程中,內存泄漏是一個(gè)普遍問(wèn)題。避免內存泄漏的第一步,就是要了解他們發(fā)生的原因。這篇文章就是要介紹一些常見(jiàn)的缺陷,然后提供一些非常好的實(shí)踐例子來(lái)指導你寫(xiě)出沒(méi)有內存泄漏的代碼。一旦你的程序存在內存泄漏,要查明代碼中引起泄漏的原因是很困難的。同時(shí)這篇文章也要介紹一個(gè)新的工具來(lái)查找內存泄漏,然后指明發(fā)生的根本原因。這個(gè)工具容易上手,可以讓你找到產(chǎn)品級系統中的內存泄漏。
垃圾回收(GC)的角色
雖然垃圾回收關(guān)心著(zhù)大部分的問(wèn)題,包括內存管理,使得程序員的任務(wù)顯得更加輕松,但是程序員還是可能犯些錯誤導致內存泄漏問(wèn)題。GC(垃圾回收)通過(guò)遞歸對所有從“根”對象(堆棧中的對象,靜態(tài)數據成員,JNI句柄等等)繼承下來(lái)的引用進(jìn)行工作,然后標記所有可以訪(fǎng)問(wèn)的活著(zhù)的對象。而這些對象變成了程序唯一能夠操縱的對象,其他的對象都被釋放了。因為GC使得程序不能夠訪(fǎng)問(wèn)那些被釋放的對象,所以這樣做是安全的。
內存管理可以說(shuō)是自動(dòng)的,但是這并沒(méi)有讓程序員脫離內存管理問(wèn)題。比方說(shuō),對于內存的分配(還有釋放)總是存在一定的開(kāi)銷(xiāo),盡管這些開(kāi)銷(xiāo)對程序員來(lái)說(shuō)是暗含的。一個(gè)程序如果創(chuàng )建了很多對象,那么它就要比完成相同任務(wù)而創(chuàng )建了較少對象的程序執行的速度慢(其他提供的內容都相同)。
文章更多想說(shuō)的,導致內存泄漏主要的原因是,先前申請了內存空間而忘記了釋放。如果程序中存在對無(wú)用對象的引用,那么這些對象就會(huì )駐留內存,消耗內存,因為無(wú)法讓垃圾回收器驗證這些對象是否不再需要。正如我們前面看到的,如果存在對象的引用,這個(gè)對象就被定義為“活著(zhù)的”,同時(shí)不會(huì )被釋放。要確定對象所占內存將被回收,程序員就要務(wù)必確認該對象不再會(huì )被使用。典型的做法就是把對象數據成員設為null或者從集合中移除該對象。注意,當局部變量不需要時(shí),不需明顯的設為null,因為一個(gè)方法執行完畢時(shí),這些引用會(huì )自動(dòng)被清理。
從更高一個(gè)層次看,這就是所有存在內存管的語(yǔ)言對內存泄漏所考慮的事情,剩余的對象引用將不再會(huì )被使用。
典型泄漏
既然我們知道了在java中確實(shí)會(huì )存在內存泄漏,那么就讓我們看一些典型的泄漏,并找出他們發(fā)生的原因。
全局集合
在大型應用程序中存在各種各樣的全局數據倉庫是很普遍的,比如一個(gè)JNDI-tree或者一個(gè)session table。在這些情況下,注意力就被放在了管理數據倉庫的大小上。當然是有一些適當的機制可以將倉庫中的無(wú)用數據移除。
可以有很多不同的解決形式,其中最常用的是一種周期運行的清除作業(yè)。這個(gè)作業(yè)會(huì )驗證倉庫中的數據然后清除一切不需要的數據。
另一個(gè)辦法是使用引用計算。集合用來(lái)對了解每個(gè)集合入口關(guān)聯(lián)器(referrer)的數目負責。這要求關(guān)聯(lián)器通知集合什么時(shí)候完成進(jìn)入。當關(guān)聯(lián)器的數目為零時(shí),就可以移除集合中的相關(guān)元素。
高速緩存
高速緩存是一種用來(lái)快速查找已經(jīng)執行過(guò)的操作結果的數據結構。因此,如果一個(gè)操作執行很慢的話(huà),你可以先把普通輸入的數據放入高速緩存,然后過(guò)些時(shí)間再調用高速緩存中的數據。
高速緩存多少還有一點(diǎn)動(dòng)態(tài)實(shí)現的意思,當數據操作完畢,又被送入高速緩存。一個(gè)典型的算法如下所示:
1.    檢查結果是否在高速緩存中,存在則返回結果;
2.    如果結果不在,那么計算結果;
3.    將結果放入高速緩存,以備將來(lái)的操作調用。
這個(gè)算法的問(wèn)題(或者說(shuō)潛在的內存泄漏)在最后一步。如果操作伴隨著(zhù)一個(gè)不同的,輸入非常大的數字,那么存入高速緩存的也是一個(gè)非常大的結果。那么這個(gè)方法就不是能夠勝任的了。
為了避免這種潛在的致命錯誤設計,程序就必須確定高速緩存在他所使用的內存中有一個(gè)上界。因此,更好的算法是:
1.    檢查結果是否在高速緩存中,存在則返回結果;
2.    如果結果不在,那么計算結果;
3.    如果高速緩存所占空間過(guò)大,移除緩存中舊的結果;
4.    將結果放入高速緩存,以備將來(lái)的操作調用。
通過(guò)不斷的從緩存中移除舊的結果,我們可以假設,將來(lái),最新輸入的數據可能被重用的幾率要遠遠大于舊的結果。這通常是一個(gè)不錯的設想。
這個(gè)新的算法會(huì )確保高速緩存的容量在預先確定的范圍內。精確的范圍是很難計算的,因為緩存中的對象存在引用時(shí)將繼續有效。正確的劃分高速緩存的大小是一個(gè)復雜的任務(wù),你必須權衡可使用內存大小和數據快速存取之間的矛盾。
另一個(gè)解決這個(gè)問(wèn)題的途徑是使用java.lang.ref.SoftReference類(lèi)堅持將對象放入高速緩存。這個(gè)方法可以保證當虛擬機用完內存或者需要更多堆的時(shí)候,可以釋放這些對象的引用。
類(lèi)裝載器
Java類(lèi)裝載器創(chuàng )建就存在很多導致內存泄漏的漏洞。由于類(lèi)裝載器的復雜結構,使得很難得到內存泄漏的透視圖。這些困難不僅僅是由于類(lèi)裝載器只與“普通的”對象引用有關(guān),同時(shí)也和對象內部的引用有關(guān),比如數據變量,方法和各種類(lèi)。這意味著(zhù)只要存在對數據變量,方法,各種類(lèi)和對象的類(lèi)裝載器,那么類(lèi)裝載器將駐留在JVM中。既然類(lèi)裝載器可以同很多的類(lèi)關(guān)聯(lián),同時(shí)也可以和靜態(tài)數據變量關(guān)聯(lián),那么相當多的內存就可能發(fā)生泄漏。
定位內存泄漏
常常地,程序內存泄漏的最初跡象發(fā)生在出錯之后,得到一個(gè)OutOfMemoryError在你的程序中。這種典型地情況發(fā)生在產(chǎn)品環(huán)境中,而在那里,你希望內存泄漏盡可能的少,調試的可能性也達到最小。也許你的測試環(huán)境和產(chǎn)品的系統環(huán)境不盡相同,導致泄露的只會(huì )在產(chǎn)品中揭示。這種情況下,你需要一個(gè)低內務(wù)操作工具來(lái)監聽(tīng)和尋找內存泄漏。同時(shí),你還需要把這個(gè)工具同你的系統聯(lián)系起來(lái),而不需要重新啟動(dòng)他或者機械化你的代碼。也許更重要的是,當你做分析的時(shí)候,你需要能夠同工具分離而使得系統不會(huì )受到干擾。
一個(gè)OutOfMemoryError常常是內存泄漏的一個(gè)標志,有可能應用程序的確用了太多的內存;這個(gè)時(shí)候,你既不能增加JVM的堆的數量,也不能改變你的程序而使得他減少內存使用。但是,在大多數情況下,一個(gè)OutOfMemoryError是內存泄漏的標志。一個(gè)解決辦法就是繼續監聽(tīng)GC的活動(dòng),看看隨時(shí)間的流逝,內存使用量是否會(huì )增加,如果有,程序中一定存在內存泄漏。
詳細輸出
有很多辦法來(lái)監聽(tīng)垃圾回收器的活動(dòng)。也許運用最廣泛的就是以:-Xverbose:gc選項運行JVM,然后觀(guān)察輸出結果一段時(shí)間。
[memory] 10.109-10.235: GC 65536K->16788K (65536K), 126.000 ms
箭頭后的值(在這個(gè)例子中 16788K)是垃圾回收后堆的使用量。
控制臺
觀(guān)察這些無(wú)盡的GC詳細統計輸出是一件非常單調乏味的事情。好在有一些工具來(lái)代替我們做這些事情。The JRockit Management Console可以用圖形的方式輸出堆的使用量。通過(guò)觀(guān)察圖像,我們可以很方便的觀(guān)察堆的使用量是否伴隨時(shí)間增長(cháng)。
 
Figure 1. The JRockit Management Console
管理控制臺甚至可以配置成在堆使用量出現問(wèn)題(或者其他的事件發(fā)生)時(shí)向你發(fā)送郵件。這個(gè)顯然使得監控內存泄漏更加容易。
內存泄漏探測工具
有很多專(zhuān)門(mén)的內存泄漏探測工具。其中The JRockit Memory Leak Detector可以供來(lái)觀(guān)察內存泄漏也可以針對性地找到泄漏的原因。這個(gè)強大的工具被緊密地集成在JRockit JVM中,可以提供最低可能的內存事務(wù)也可以輕松的訪(fǎng)問(wèn)虛擬機的堆。
專(zhuān)門(mén)工具的優(yōu)勢
一旦你知道程序中存在內存泄漏,你需要更專(zhuān)業(yè)的工具來(lái)查明為什么這里會(huì )有泄漏。而JVM是不可能告訴你的?,F在有很多工具可以利用了。這些工具本質(zhì)上主要通過(guò)兩種方法來(lái)得到JVM的存儲系統信息的:JVMTI和字節碼使用儀器。Java虛擬機工具接口(JVMTI)和他的原有形式JVMPI(壓型接口)都是標準接口,作為外部工具同JVM進(jìn)行通信,搜集JVM的信息。字節碼使用儀器則是引用通過(guò)探針獲得工具所需的字節信息的預處理技術(shù)。
通過(guò)這些技術(shù)來(lái)偵測內存泄漏存在兩個(gè)缺點(diǎn),而這使得他們在產(chǎn)品級環(huán)境中的運用不夠理想。首先,根據兩者對內存的使用量和內存事務(wù)性能的降級是不可以忽略的。從JVM獲得的堆的使用量信息需要在工具中導出,收集和處理。這意味著(zhù)要分配內存。按照JVM的性能導出信息是需要開(kāi)銷(xiāo)的,垃圾回收器在搜集信息的時(shí)候是運行的非常緩慢的。另一個(gè)缺點(diǎn)就是,這些工具所需要的信息是關(guān)系到JVM的。讓工具在JVM開(kāi)始運行的時(shí)候和它關(guān)聯(lián),而在分析的時(shí)候,分離工具而保持JVM運行,這顯然是不可能的。
既然JRockit Memory Leak Detector是被集成到JVM中的,那么以上兩種缺點(diǎn)就不再適用。首先,大部分的處理和分析都是在JVM中完成的,所以就不再需要傳送或重建任何數據。處理也可以在垃圾回收器的背上,他的意思是提高速度。再有,內存泄漏偵測器可以同一個(gè)運行的JVM關(guān)聯(lián)和分離,只要JVM在開(kāi)始的時(shí)候伴隨著(zhù) ?Xmanagement選項(這個(gè)允許監聽(tīng)和管理JVM通過(guò)遠程JMX接口)。當工具分離以后,工具不會(huì )遺留任何東西在JVM中;JVM就可以全速運行代碼就好像工具關(guān)聯(lián)之前一樣。
趨勢分析
讓我們更深一步來(lái)觀(guān)察這個(gè)工具,了解他如何捕捉到內存泄漏。在你了解到代碼中存在內存泄漏,第一步就是嘗試計算出什么數據在泄漏??哪個(gè)對象類(lèi)導致泄露。The JRockit Memory Leak Detector通過(guò)在垃圾回收的時(shí)候,計算每個(gè)類(lèi)所包含的現有的對象來(lái)達到目的。如果某一個(gè)類(lèi)的對象成員數目隨著(zhù)時(shí)間增長(cháng)(增長(cháng)率),那么這里很可能存在泄漏。
 
Figure 2. The trend analysis view of the Memory Leak Detector
因為一個(gè)泄漏很可能只是像水滴一樣小,所以趨勢分析必須運行足夠長(cháng)的一段時(shí)間。在每個(gè)短暫的時(shí)間段里,局部類(lèi)的增加會(huì )使得泄漏發(fā)生推遲。但是,內存事務(wù)是非常小的(最大的內存事務(wù)是由在每個(gè)垃圾回收時(shí)從JRockit向內存泄漏探測器發(fā)送的一個(gè)數據包組成的)。內存事務(wù)不應該成為任何系統的問(wèn)題??甚至一個(gè)在產(chǎn)品階段全速運行的程序。
一開(kāi)始,數字會(huì )有很大的跳轉,隨時(shí)間的推進(jìn),這些數字會(huì )變得穩定,而后顯示哪些類(lèi)會(huì )不斷的增大。
尋找根本原因
知道那些對象的類(lèi)會(huì )導致泄露,有時(shí)候足夠制止泄露問(wèn)題。這個(gè)類(lèi)也許只是被用在非常有限的部分,通過(guò)快速的視察就可以找到問(wèn)題所在。不幸的是,這些信息是不夠的。比方說(shuō),經(jīng)常導致內存泄漏的對象類(lèi)java.lang.String,然而String類(lèi)被應用于整個(gè)程序,這就變得有些無(wú)助。
我們想知道的是其他的對象是否會(huì )導致內存泄漏,好比上面提到的String類(lèi),為什么這些導致泄漏的對象還是存在周?chē)??那些引用是指向這些對象的?這里一列的對象存有對String類(lèi)的引用,就會(huì )變得太大而沒(méi)有實(shí)際意義。為了限制數據的數量,我們可以通過(guò)類(lèi)把他們編成一個(gè)組,這樣我們就可以看到,那些其他類(lèi)的對象會(huì )依然泄漏對象(String類(lèi))。比如,將一個(gè)String類(lèi)放入Hashtable,那里我們可以看到關(guān)聯(lián)到String類(lèi)的Hashtable入口。從Hashtable入口向后運行,我們終于找到那些關(guān)聯(lián)到String類(lèi)的Hashtable對象(參看圖三如下)。
 
Figure 3. Sample view of the type graph as seen in the tool
向后工作
自從開(kāi)始我們就一直著(zhù)眼于對象類(lèi),而不是單獨的對象,我們不知道那個(gè)Hashtable存在泄漏。如果我們可以找出所有的Hashtable在系統中有多大,我們可以假設最大的那個(gè)Hashtable存在泄漏(因為它可以聚集足夠的泄漏而變得很大)。因此,所有Hashtable,同時(shí)有和所有他們所涉及的數據,可以幫助我們查明導致泄露的精確的Hashtable。
 
Figure 4. Screenshot of the list of Hashtable objects and the size of the data they are holding live
計算一個(gè)對象所涉及的數據的開(kāi)銷(xiāo)是非常大的(這要求引用圖表伴隨著(zhù)那個(gè)對象作為根運行)而且如果對每一個(gè)對象都這樣處理,就需要很多時(shí)間。知道一些關(guān)于Hashtable內部的實(shí)現機制可以帶來(lái)捷徑。在內部,一個(gè)Hashtable有一個(gè)Hashtable的數組入口。數組的增長(cháng)伴隨著(zhù)Hashtable中對象的增長(cháng)。因此,要找到最大的Hashtable,我們可以把搜索限制在尋找包含Hashtable引用入口的最大的數組。這樣就更快捷了。
 
Figure 5. Screenshot of the listing of the largest Hashtable entry arrays, as well as their sizes.
向下深入
當我們發(fā)現了存在泄漏的Hashtable的實(shí)例,就可以順藤摸瓜找到其他的引用這些Hashtable的實(shí)例,然后用上面的方法來(lái)找到是那個(gè)Hashtable存在問(wèn)題。
 
Figure 6. This is what an instance graph can look like in the tool.
舉個(gè)例子,一個(gè)Hashtable可以有一個(gè)來(lái)自MyServer的對象的引用,而MyServer包含一個(gè)activeSessions數據成員。這些信息就足夠深入代碼找出問(wèn)題所在。
 
Figure 7. Inspecting an object and its references to other objects
找出分配點(diǎn)
當發(fā)現了內存泄漏問(wèn)題,找到那些泄漏的對象在何處是非常有用的。也許沒(méi)有足夠的信息知道他們同其他相關(guān)對象之間的聯(lián)系,但是關(guān)于他們在那里被創(chuàng )建的信息還是很有幫助的。當然,你不會(huì )愿意創(chuàng )建一個(gè)工具來(lái)打印出所有分配的堆棧路徑。你也不會(huì )愿意在模擬環(huán)境中運行程序只是為了捕捉到一個(gè)內存泄漏。
有了JRockit Memory Leak Detector,程序代碼可以動(dòng)態(tài)的在內存分配出創(chuàng )建堆棧路徑。這些堆棧路徑可以在工具中累積,分析。如果你不啟用這個(gè)工具,這個(gè)特征就不會(huì )有任何消耗,這就意味著(zhù)時(shí)刻準備著(zhù)開(kāi)始。當需要分配路徑時(shí),JRockit的編譯器可以讓代碼不工作,而監視內存分配,但只對需要的特定類(lèi)有效。更好的是,當做完數據分析后,生成的機械代碼會(huì )完全被移除,不會(huì )引起任何執行上的效率衰退。
 
Figure 8. The allocation stack traces for String during execution of a sample program
總結
內存泄漏查找起來(lái)非常困難,文章中的一些避免泄漏的好的實(shí)踐,包括了要時(shí)刻記住把什么放進(jìn)了數據結構中,更接近的監視內存中意外的增長(cháng)。
我們同時(shí)也看到了JRockit Memory Leak Detector是如何捕捉產(chǎn)品級系統中的內存泄漏的。該工具通過(guò)三步的方法發(fā)現泄漏。一,通過(guò)趨勢分析發(fā)現那些對象類(lèi)存在泄漏;二,找出同泄漏對象相關(guān)的其他類(lèi);三,向下發(fā)掘,觀(guān)察獨立的對象之間是如何相互聯(lián)系的。同時(shí),該工具也可以動(dòng)態(tài)的,找出所有內存分配的堆棧路徑。利用這三個(gè)特性,將該工具緊緊地集成在JVM中,那么就可以安全的,有效的捕捉和修復內存泄漏了。
資源
•    JRockit Tools Download 
•    BEA JRockit 5.0 Documentation 
•    New Features and Tools in JRockit 5.0 
•    BEA JRockit DevCenter 
Staffan Larsen是JRockit產(chǎn)品的工程師之一,這個(gè)產(chǎn)品是在1998年底聯(lián)合創(chuàng )建的。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
消除內存泄漏
java內存泄露 - 心靈花園 - JavaEye技術(shù)網(wǎng)站
Java垃圾收集算法與內存泄露
使用JRockit作為工具檢測并解決JAVA內存泄漏問(wèn)題的一次實(shí)戰
九大工具助你玩轉Java性能優(yōu)化
Java8 為什么使用元空間替代永久代,這樣做有什么好處呢?
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久