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

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

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

開(kāi)通VIP
編程中國-Java 理論與實(shí)踐: 用弱引用堵住內存泄漏
C語(yǔ)言
VB
C++
VC++
JAVA
Delphi
匯編
數據結構
軟件工程
C技術(shù)資料
C語(yǔ)言教程
基礎教程
編程技巧
控件集錦
編程實(shí)例
優(yōu)化技術(shù)
C++教程
C++技術(shù)資料
VC教程
VC技術(shù)資料
JAVA教程
JAVA技術(shù)資料
Delphi教程
Delphi技術(shù)資料
匯編教程
匯編技術(shù)資料
匯編源碼
ASP
JSP
PHP
JavaScript
XML
ASP教程
ASP技術(shù)資料
JSP教程
JSP技術(shù)資料
php教程
PHP技術(shù)資料
JavaScript教程
JavaScript技術(shù)資料
XML教程
XML技術(shù)資料
ASP.NET
C#
VB.NET
VC.NET
J#.NET
Jscript.NET
ASP.NET教程
ASP.NET技術(shù)資料
C#教程
C#技術(shù)資料
VB.NET教程
VB.NET技術(shù)資料
VC.NET教程
VC.NET技術(shù)資料
ACCESS
VFP
SQL Server
MySQL
Oracle
PowerBuilder
ACCESS教程
ACCESS技術(shù)資料
VFP教程
VFP技術(shù)資料
SQL Server教程
SQL Server技術(shù)資料
MySQL教程
MySQL技術(shù)資料
PB教程
PB技術(shù)資料
Windows
Linux
Unix
HTML
FrontPage
Dreamweaver
HTML教程
HTML技術(shù)資料
FrontPage教程
FrontPage技術(shù)資料
雖然用Java? 語(yǔ)言編寫(xiě)的程序在理論上是不會(huì )出現“內存泄漏”的,但是有時(shí)對象在不再作為程序的邏輯狀態(tài)的一部分之后仍然不被垃圾收集。本月,負責保障應用程序健康的工程師 Brian Goetz 探討了無(wú)意識的對象保留的常見(jiàn)原因,并展示了如何用弱引用堵住泄漏。
要讓垃圾收集(GC)回收程序不再使用的對象,對象的邏輯 生命周期(應用程序使用它的時(shí)間)和對該對象擁有的引用的實(shí)際 生命周期必須是相同的。在大多數時(shí)候,好的軟件工程技術(shù)保證這是自動(dòng)實(shí)現的,不用我們對對象生命周期問(wèn)題花費過(guò)多心思。但是偶爾我們會(huì )創(chuàng )建一個(gè)引用,它在內存中包含對象的時(shí)間比我們預期的要長(cháng)得多,這種情況稱(chēng)為無(wú)意識的對象保留(unintentional object retention)。
全局 Map 造成的內存泄漏
無(wú)意識對象保留最常見(jiàn)的原因是使用 Map 將元數據與臨時(shí)對象(transient object)相關(guān)聯(lián)。假定一個(gè)對象具有中等生命周期,比分配它的那個(gè)方法調用的生命周期長(cháng),但是比應用程序的生命周期短,如客戶(hù)機的套接字連接。需要將 一些元數據與這個(gè)套接字關(guān)聯(lián),如生成連接的用戶(hù)的標識。在創(chuàng )建 Socket 時(shí)是不知道這些信息的,并且不能將數據添加到 Socket 對象上,因為不能控制 Socket 類(lèi)或者它的子類(lèi)。這時(shí),典型的方法就是在一個(gè)全局 Map 中存儲這些信息,如清單 1 中的 SocketManager 類(lèi)所示:
清單 1. 使用一個(gè)全局 Map 將元數據關(guān)聯(lián)到一個(gè)對象
public class SocketManager {
private Map<Socket,User> m = new HashMap<Socket,User>();
public void setUser(Socket s, User u) {
m.put(s, u);
}
public User getUser(Socket s) {
return m.get(s);
}
public void removeUser(Socket s) {
m.remove(s);
}
}
SocketManager socketManager;
...
socketManager.setUser(socket, user);
這種方法的問(wèn)題是元數據的生命周期需要與套接字的生命周期掛鉤,但是除非準確地知道什么時(shí)候程序不再需要這個(gè)套接字,并記住從 Map 中刪除相應的映射,否則,Socket 和 User 對象將會(huì )永遠留在 Map 中,遠遠超過(guò)響應了請求和關(guān)閉套接字的時(shí)間。這會(huì )阻止 Socket 和 User 對象被垃圾收集,即使應用程序不會(huì )再使用它們。這些對象留下來(lái)不受控制,很容易造成程序在長(cháng)時(shí)間運行后內存爆滿(mǎn)。除了最簡(jiǎn)單的情況,在幾乎所有情況下找出 什么時(shí)候 Socket 不再被程序使用是一件很煩人和容易出錯的任務(wù),需要人工對內存進(jìn)行管理。
找出內存泄漏
程序有內存泄漏的第一個(gè)跡象通常是它拋出一個(gè) OutOfMemoryError,或者因為頻繁的垃圾收集而表現出糟糕的性能。幸運的是,垃圾收集可以提供能夠用來(lái)診斷內存泄漏的大量信息。如果以 -verbose:gc 或者 -Xloggc 選項調用 JVM,那么每次 GC 運行時(shí)在控制臺上或者日志文件中會(huì )打印出一個(gè)診斷信息,包括它所花費的時(shí)間、當前堆使用情況以及恢復了多少內存。記錄 GC 使用情況并不具有干擾性,因此如果需要分析內存問(wèn)題或者調優(yōu)垃圾收集器,在生產(chǎn)環(huán)境中默認啟用 GC 日志是值得的。
有工具可以利用 GC 日志輸出并以圖形方式將它顯示出來(lái),JTune 就是這樣的一種工具(請參閱 參考資料)。觀(guān)察 GC 之后堆大小的圖,可以看到程序內存使用的趨勢。對于大多數程序來(lái)說(shuō),可以將內存使用分為兩部分:baseline 使用和 current load 使用。對于服務(wù)器應用程序,baseline 使用就是應用程序在沒(méi)有任何負荷、但是已經(jīng)準備好接受請求時(shí)的內存使用,current load 使用是在處理請求過(guò)程中使用的、但是在請求處理完成后會(huì )釋放的內存。只要負荷大體上是恒定的,應用程序通常會(huì )很快達到一個(gè)穩定的內存使用水平。如果在應用 程序已經(jīng)完成了其初始化并且負荷沒(méi)有增加的情況下,內存使用持續增加,那么程序就可能在處理前面的請求時(shí)保留了生成的對象。
清單 2 展示了一個(gè)有內存泄漏的程序。MapLeaker 在線(xiàn)程池中處理任務(wù),并在一個(gè) Map 中記錄每一項任務(wù)的狀態(tài)。不幸的是,在任務(wù)完成后它不會(huì )刪除那一項,因此狀態(tài)項和任務(wù)對象(以及它們的內部狀態(tài))會(huì )不斷地積累。
清單 2. 具有基于 Map 的內存泄漏的程序
public class MapLeaker {
public ExecutorService exec = Executors.newFixedThreadPool(5);
public Map<Task, TaskStatus> taskStatus
= Collections.synchronizedMap(new HashMap<Task, TaskStatus>());
private Random random = new Random();
private enum TaskStatus { NOT_STARTED, STARTED, FINISHED };
private class Task implements Runnable {
private int[] numbers = new int[random.nextInt(200)];
public void run() {
int[] temp = new int[random.nextInt(10000)];
taskStatus.put(this, TaskStatus.STARTED);
doSomeWork();
taskStatus.put(this, TaskStatus.FINISHED);
}
}
public Task newTask() {
Task t = new Task();
taskStatus.put(t, TaskStatus.NOT_STARTED);
exec.execute(t);
return t;
}
}
圖 1 顯示 MapLeaker GC 之后應用程序堆大小隨著(zhù)時(shí)間的變化圖。上升趨勢是存在內存泄漏的警示信號。(在真實(shí)的應用程序中,坡度不會(huì )這么大,但是在收集了足夠長(cháng)時(shí)間的 GC 數據后,上升趨勢通常會(huì )表現得很明顯。)
圖 1. 持續上升的內存使用趨勢
確信有了內存泄漏后,下一步就是找出哪種對象造成了這個(gè)問(wèn)題。所有內存分析器都可以生成按照對象類(lèi)進(jìn)行分解的堆快照。有一些很好的商業(yè)堆分析工 具,但是找出內存泄漏不一定要花錢(qián)買(mǎi)這些工具 —— 內置的 hprof 工具也可完成這項工作。要使用 hprof 并讓它跟蹤內存使用,需要以 -Xrunhprof:heap=sites 選項調用 JVM。
清單 3 顯示分解了應用程序內存使用的 hprof 輸出的相關(guān)部分。(hprof 工具在應用程序退出時(shí),或者用 kill -3 或在 Windows 中按 Ctrl+Break 時(shí)生成使用分解。)注意兩次快照相比,Map.Entry、Task 和 int[] 對象有了顯著(zhù)增加。
請參閱 清單 3。
清單 4 展示了 hprof 輸出的另一部分,給出了 Map.Entry 對象的分配點(diǎn)的調用堆棧信息。這個(gè)輸出告訴我們哪些調用鏈生成了 Map.Entry 對象,并帶有一些程序分析,找出內存泄漏來(lái)源一般來(lái)說(shuō)是相當容易的。
清單 4. HPROF 輸出,顯示 Map.Entry 對象的分配點(diǎn)
TRACE 300446:
Java.util.HashMap$Entry.<init>(<Unknown Source>:Unknown line)
Java.util.HashMap.addEntry(<Unknown Source>:Unknown line)
Java.util.HashMap.put(<Unknown Source>:Unknown line)
Java.util.Collections$SynchronizedMap.put(<Unknown Source>:Unknown line)
com.quiotix.dummy.MapLeaker.newTask(MapLeaker.Java:48)
com.quiotix.dummy.MapLeaker.main(MapLeaker.Java:64)
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java 理論與實(shí)踐: 用弱引用堵住內存泄漏
ANDROID 探究oom內幕
內存分析工具 MAT 的使用
Android內存泄漏分析及調試
Android Monitor工具詳解大全
Android性能優(yōu)化之內存泄漏
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

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