Flash Player 9中的資源管理策略
原文
Resource management strategies in Flash Player 9
翻譯
Actionscript 3.0帶給Flash開發(fā)人員更加快的代碼執(zhí)行和許多新的API增強(qiáng),站在開發(fā)人員的立足點來說,相對之前的版本這些改變需要更高級別的可靠性。本文重點討論Actionscript 3.0中新資源管理特性,以及粗略的討論下Actionscript 3.0中那些可以幫助您跟蹤和更加有效的管理內(nèi)存的工具。
Actionscript 3.0中影響資源管理的最大的改變是其新的顯示列表模型。在Flash Player 8及之前版本中,當(dāng)一個顯示(display)對象被從屏幕被移除時(使用removeMovie 或 unloadMovie),該顯示對象及其子對象將被立即從內(nèi)存總移除并且代碼即可終止,F(xiàn)lash Player 9帶來了更加靈活的顯示列表模型,在該模型中,將顯示對象(sprites、movie clips等)作為普通對象一樣對待。
這意味著開發(fā)人員現(xiàn)在可以做一些真正酷的事情,比如重排根目錄(reparenting:將顯示對象從一個顯示列表移到另一中)和從已經(jīng)載入的SWF中實例化顯示對象。不幸的是,它也同時意味著現(xiàn)在顯示對象與其他別的對象一樣被垃圾收集器同等對待,它帶來了大量有意思(可能不明顯)的問題。
為什么資源管理是個問題
Flash開發(fā)人員看了Actionscript 3.0中這些新的資源管理考慮可能覺得概念很復(fù)雜,另一方面,Java開發(fā)人員可能覺得沒什么。這些差距是可以理解的:Flash開發(fā)人員不習(xí)慣在基本的最佳的實踐之外實現(xiàn)手工資源管理——如當(dāng)不再使用時刪除引用——反之Java開發(fā)人員之前就將其貫穿所有中了。這些問題對于大多數(shù)現(xiàn)代的內(nèi)存管理語言也同樣會出現(xiàn),不幸的是,現(xiàn)在沒有完全避免它們的方法。
盡管資源管理是生活之本,F(xiàn)lash遇見了很多在其他語言中罕見的挑戰(zhàn)(包括Flex)。Flash內(nèi)容往往包含許多閑置或易交互的執(zhí)行代碼——不像Java和Flex他們大多數(shù)是交互式的。這意味著只有用戶交互時才執(zhí)行CPU密集代碼。另外,F(xiàn)lash工程比其他平臺更頻繁的從第三方資源載入(可能使用貧編碼標(biāo)準(zhǔn))外部內(nèi)容。Flash開發(fā)人員也只有更少的工具、剖析器和框架可以使用。
最后,F(xiàn)lash開發(fā)人員通常有著很少的非正式的編程工作背景。我所知道的大部分Flash開發(fā)人員有著音樂、藝術(shù)、商業(yè)、哲學(xué)或只是除編程外的任何背景。這種多元化的結(jié)果帶來另人震撼的創(chuàng)意和內(nèi)容,但是該社區(qū)卻沒有真正準(zhǔn)備好處理資源管理問題。
問題1:動態(tài)內(nèi)容
在資源管理中遇到的其中一個明顯的問題是與sprites(或其他顯示對象)有關(guān),您動態(tài)實例化它們,然后希望在以后的時間里面移除它們。當(dāng)您將顯示對象從場景中移除后,因為它們不再活動并且掛死在顯示列表中,它仍會一直存在內(nèi)存中。如果您做好了清除它的所有引用的工作,那們在下次垃圾收集器運行收集時,該剪接將會被從內(nèi)存中移除。基于松散內(nèi)存管理使用的特性,這將有很多不確定性。
注意到這一點非常的重要,顯示對象不只一直占用內(nèi)存,它還會一直執(zhí)行“空閑”代碼,如定時器、進(jìn)入幀以及監(jiān)聽是否從某一范圍出來的監(jiān)聽器。
以下幾個示例可以幫助您說明該問題:
某一游戲sprite監(jiān)聽它自己的enterFrame事件,每次幀移動時,該應(yīng)用就會處理某些計算以決定它是否接近其他游戲元素。在Actionscript 3.0中,即使您已經(jīng)將該sprite從顯示列表中移除并將所有對它的應(yīng)用都置為null,除非它已經(jīng)被垃圾收集器給移除后,在每個幀移動時,該應(yīng)用仍會一直運行該代碼。您必須記住要當(dāng)該sprite并移除時必須明確將enterFrame監(jiān)聽器移除。
考慮一個通過注冊場景的mouseMove來跟隨鼠標(biāo)的電影片段(movie clip)——在新的事件模型下這是達(dá)到該效果的唯一方式。除非您記得移除監(jiān)聽器,每次鼠標(biāo)移動時,該片段將一直會執(zhí)行該代碼,即使在片段被“刪除”后。缺省的,因為場景中為了事件發(fā)布有一個指向它的引用,該片段一直會執(zhí)行。我將在后面的文章中討論如何避免這樣的問題
現(xiàn)在想象一下以上示例蘊含的含義,在垃圾收集器回收前移除多個sprites——或者如果移除某一sprites所有的引用失敗會發(fā)生什么。您很容易一不小心就超出CPU最大處理能力,進(jìn)而使得您的應(yīng)用或游戲慢得像在爬,甚至搞得用戶計算機(jī)完全停頓。當(dāng)前還沒有辦法強(qiáng)行讓Flash Player殺死一個顯示對象并停止它的執(zhí)行。至多只能在該對象被從顯示中移除時由Flash開發(fā)人員在手動這樣做。
問題2:已載入的內(nèi)容
記住現(xiàn)在已載入的SWF的內(nèi)容也是和其他別的對象一樣被同等對待的,并且您可以開始想象下您在載入內(nèi)容時可能會遭遇到的某些問題。類似其他顯示對象,當(dāng)前沒有方法可以直接將已載入SWF和它的內(nèi)容從內(nèi)容中移除。調(diào)用Loader.unload只是簡單將載入器指向SWF的應(yīng)用置空;它將繼續(xù)存在并保持執(zhí)行直到它被下次垃圾收集器回收掉(確保所有對已載入內(nèi)容的其他引用都已被完整的清除)。
考慮以下兩個場景:
您創(chuàng)建一個用來載入您的實驗Flash工程的shell。這一實驗工作是尖端技術(shù),并把CPU的資源已經(jīng)用到了極限 。某一用戶點擊某一按鈕來載入一個實驗,查看它,然后再點擊某一按鈕來載入第二個實驗,如果到第一個實驗的所有引用都已經(jīng)被清除,它將繼續(xù)在后臺運行,當(dāng)?shù)诙€實驗在同一時刻運行時,很可能會出現(xiàn)最大處理能力溢出。
某一客戶委托您創(chuàng)建一個應(yīng)用來載入其他開發(fā)人員創(chuàng)建的Actionscript 3.0 SWFs。該開發(fā)人員增加了到場景的監(jiān)聽器或其他別的如創(chuàng)建了一個到其自己內(nèi)容的外部引用,它將內(nèi)存中活動并且繼續(xù)消耗CPU資源直到用戶退出您的應(yīng)用。就算該載入的內(nèi)容沒有任何外部引用,它仍然會繼續(xù)無限期的執(zhí)行直到被下次垃圾收集器回收。
當(dāng)您設(shè)計一個載入不可信內(nèi)容的應(yīng)用時,覺察到這非常重要——在您卸載它后該代碼仍會繼續(xù)執(zhí)行。雖然該內(nèi)容會遵循Flash Player安全模型規(guī)范運行,但在您的應(yīng)用開發(fā)過程中考慮一些潛在的漏洞仍然是一個好主意。
使用System.totalMemory
盡管System.totalMemory是一個簡單工具,但它是重要的因為在Flash中它是開發(fā)人員可以使用的第一個運行時剖析工具。它可以讓您監(jiān)控Flash Player運行時用了多少內(nèi)存。這使得您在開發(fā)中有一定的能力調(diào)整您自己工作而不用使用系統(tǒng)監(jiān)視器。更重要的,它使得您可以在給用戶帶來一系列問題前超前的處理您的內(nèi)容中的重大內(nèi)存泄露成為可能。釋出一個錯誤然后終止您的應(yīng)用總是好于使用戶系統(tǒng)停頓或者甚至完全的死機(jī)。
這是一個您如何可以做到這的簡單示例:
import flash.system.System;
import flash.net.navigateToURL;
import flash.net.URLRequest;
...
// check our memory every 1 second:
// 每秒檢查一下我們的內(nèi)存:
var checkMemoryIntervalID:uint = setInterval(checkMemoryUsage,1000);
...
var showWarning:Boolean = true;
var warningMemory:uint = 1000*1000*500;
var abortMemory:uint = 1000*1000*625;
...
function checkMemoryUsage() {
if (System.totalMemory > warningMemory && showWarning) {
// show an error to the user warning them that we're running out of memory and might quit
// 向用戶顯示一個錯誤警告他們我們內(nèi)存溢出并且可能要退出了
// try to free up memory if possible
// 如果可能的話試圖釋放內(nèi)存
showWarning = false; // so we don't show an error every second
} else if (System.totalMemory > abortMemory) {
// save current user data to an LSO for recovery later?
// 將用戶數(shù)據(jù)保存到LSO中以在以后恢復(fù)?
abort();
}
}
function abort() {
// send the user to a page explaining what happpened:
// 發(fā)送給用戶一個頁面解釋發(fā)生了什么:
navigateToURL(new URLRequest("memoryError.html"));
}
很明顯以上代碼還有很多方式可以增強(qiáng),但是希望該代碼能夠演示該處理背后的基本概念。
注意到總內(nèi)存(totalMemory)是單一進(jìn)程中的共享值是重要的。一個單一進(jìn)程可能只是一個瀏覽器窗口,或者所有打開的瀏覽器窗口,視乎于瀏覽器、操作系統(tǒng)以及該窗口是符合打開的。例如,在Mac OS X中,所有的Safari瀏覽器窗口共享一個單一的進(jìn)程和總內(nèi)存(totalMemory)值。而在Microsoft Windows中進(jìn)程數(shù)和占用內(nèi)存值就更加的費解。
弱引用
在Actionscript 3.0 中其中一個我真的很高興看到的特性是弱引用的實現(xiàn)。它可以描述為不被垃圾收集器計算以決定某一對象是否可以被收集的對對象的引用。如果某一對象剩余的唯一的引用是弱引用的話,那們該對象將在垃圾收集器的下次運行時被移除。
不幸的是,弱引用只在兩種情況下支持。第一是事件監(jiān)聽器——這太偉大了因為事件監(jiān)聽器是導(dǎo)致垃圾收集問題的最常見引用之一。我強(qiáng)烈的推薦您總是在監(jiān)聽器上使用弱引用。要做到這點,要在調(diào)用addEventListener時給第五個參數(shù)傳遞true,如下所示:
someObj.addEventListener("eventName",listenerFunction,useCapture,priority,weakReference);
stage.addEventListener(Event.CLICK,handleClick,false,0,true);
// the reference back to handleClick (and this object) will be weak.
// 到 handleClick(和該對象)的引用將是弱的。
關(guān)于本章節(jié)要更多了解,請閱讀我blog上的關(guān)于弱引用監(jiān)聽的文章。
Actionscript 3.0還在字典對象(Dictionary object)中支持弱引用。只需要在實例一個新的字典事向第一個參數(shù)傳遞true即可讓它使用弱引用作為它的關(guān)鍵字。如下所示:
var dict:Dictionary = new Dictionary(true);
dict[myObj] = myOtherObj;
// the reference to myObj is weak, the reference to myOtherObj is strong
// 指向myObj的引用是弱的,指向myOtherObj的引用是強(qiáng)的。
從這里通往何方
資源管理是Actionscript 3.0 開發(fā)的重要部分。忽略本文中描述的問題可能的結(jié)果就是遲緩的內(nèi)容(應(yīng)用),此外,也有潛在的完全拖垮用戶系統(tǒng)的風(fēng)險。現(xiàn)在再也沒有任何方法可以直接將顯示對象從內(nèi)存中移除并且停止它的代碼執(zhí)行——這意味著在某一應(yīng)用中Flash開發(fā)人員有責(zé)任在對象不再需要使用的時候?qū)⑵渫耆那謇硗桩?dāng)。
雖然Actionscript 3.0實質(zhì)上提高了開發(fā)人員在他們應(yīng)用中管理資源必須做的工作量,但是在Flash Player 9提供了新的工具來幫助管理內(nèi)存的使用。將這些新工具和有效的策略和方法配對起來(關(guān)于該主題,請查看本文的姊妹篇:理解Flash Player 9垃圾收集)可以使得您在即將到來的Flash和Flex工程中成功的管理資源。
更多信息,請務(wù)必訪問Flash開發(fā)人員中心和Flash Player開發(fā)人員中心。
posted on 2008-08-07 20:21 vinny 閱讀(293) 評論(0) 編輯 收藏 所屬分類: Flex