關於Flash記憶體清理

來源:互聯網
上載者:User

Flash Player的garbage collection(GC)分兩種運行方式,一種是“引用計數法”(Reference Counting),一種是“標記-清除法”(Mark Sweeping)。

引用計數法是通過計算指向某個對象的引用的數量來確定是否清除該對象。如果一個對象的引用數量為0,表示程式無法再訪問到該對象,則清除該對象;如果引用計數不為0,則不清除。這種方法運行代價較小,但是這種方法無法清除存在循環參考關係的對象集合。標記-清除法是從程式的根對象開始,遍曆每個引用指向的對象。遍曆經過的對象,則將其標記。最後清除所有沒有打上標記的對象。這種方法比較徹底,但是運行代價較高。

FlashPlayer運行GC的時間並不固定,它會根據你的記憶體的佔用情況來決定運行GC的時間。它會根據使用者機器的記憶體值來設定一個閥值,然後將程式的佔用記憶體量儲存在該閥值左右。

詳細可查看文章“Understanding garbage collection in Flash Player 9”。

正因為FlashPlayer這種“不確定”的GC機制,所以我們所要做的主要工作是確保建立的對象在不需要的時候可以被釋放。確保對象可以被釋放的大原則是沒有外部參考指向該對象,除了一般情況下的沒有將外部參考顯示地設為null之外,以下的情況也會導致對象無法釋放:

1. 沒有remove監聽的事件。比如,A對象對某個事件進行監聽,監聽函數(Event Handler)存在於B對象中,則相當於A對象會儲存一個B對象的方法的引用,會導致B對象的記憶體無法釋放。
解決方案:注意remove掉監聽事件;或者在調用addEventListener()時,將監聽函數設為弱引用,但這種做法只適合一次性的監聽。

2. 使用BindingUtils.bindSetter()、ChangeWatcher.watch()綁定某個對象之後,沒有清除該綁定。道理同1,其實綁定某個對象,也就是監聽其發出的PropertyChange事件。
解決方案:使用ChangeWatcher.unwatch()來清除綁定關係。

3. 聲明了樣式,並在樣式中使用了嵌入式資源。比如在<mx:Style>標籤中定義了樣式名稱。一個對象定義了樣式,相當於對外聲明了一個全域可用的樣式,因此會到導致外部儲存了該對象的引用,可能導致對象無法釋放。
解決方案:解決方案很多,可以使用動態載入的樣式,或者使用一個類或模組(Module)專門管理樣式,這些解決方案取決程式的架構設計。

4. 使用ExternalInface.callBack()聲明了對外的API函數。類似於情況1,一個對象對外聲明了API,就使外部儲存了指向該對象的引用。
解決方案:如果之前使用了ExternalInface.callBack("APIName", functionName)聲明了一個API,則可以使用ExternalInface.callBack("APIName", null)取消該API。

5. 某些控制項(類似TextInput),或者由這類控制項構成的自訂群組件,當焦點在這些控制項上時,即使從DisplayList移除掉這些控制項並刪除引用,這些控制項對象也無法釋放。這個問題還有人提出來是一個Bug(http://bugs.adobe.com/jira/browse/SDK-14781)。這個問題估計和flash的焦點管理機制有關。
解決方案:目前的解決方案只能是等焦點重新轉移到其他控制項上(比如點擊了其他控制項),如此之前的控制項對象就可以被GC釋放。

那應該在什麼時候做好垃圾清理的準備工作呢?之前有的文章說應該監聽組件的removeFromStage事件,在其處理方法中進行垃圾清理的準備工作(清除引用,刪除監聽器,清除綁定關係,取消對外API等工作)。
其實這種方法不太確切。因為removedFromStage事件是當組件從DisplayList上移除的時候發出的,並不代表該組件對象的生命週期已經終結。只要程式保留了該組件對象的引用,可以再重新把該組件對象添加到DisplayList上(此時,該組件對象會發出addedToStage事件)。如果單純在removedFromStage事件的監聽函數中做該對象的垃圾清理準備工作,當組件重新被使用的時候,可能導致該組件對象原來的狀態被破壞而無法使用。
因此,比較好的實踐方法應該是,利用addedToStage、removedFromStage兩個事件的對應關係,在removedFromStage事件的處理方法中執行垃圾清理的準備工作(清除引用,刪除監聽器,清除綁定關係,取消對外API等作),而在addedToStage事件的處理方法中執行removedFromStage事件的處理方法的反操作(設定引用、添加監聽、設定綁定關係、設定API...也可以認為是一個組件對象的初始化操作),這樣就可以保證一個組件對象被從DisplayList上移除後,可以釋放相應記憶體;如果儲存其引用,並將其重新添加到DisplayList上,又可重新使用。

最後翻譯一段關於記憶體清理的建議:

原文:

1. usage of instance members instead of static members can easily be detected with the profiler (replace by static members where possible)

2. usage of weak references and / or removal of eventListeners after consumption of the event (if posible) helps reducing the memory usage

3. moduleLoader.unloadModule leaks memory, use moduleLoader.url=null instead

4. module memory is freed at arbitrary times (not at unload)

5. runnning debug version of modules leaks huge amounts of memory no matter which container is used

6. declaring modules as modules in the configuration of a flex builder 3 project (and not as applications like in FlexBuilder 2) and optimizing for a specific application reduces module size drastically

7. forcing garbageCollection (double LocalConnection.connect hack) is necessary in order to measure leaks and to keep memory under control

8. use the release version of the module swf

9. uninstall the debug flash player ("uninstall_flash_player.exe")

10. install the release version of the flash player ("install_flash_player_active_x.msi")

以下是翻譯內容:

1. 使用執行個體成員(instance members),而不是用靜態成員(static members),可以更容易地被profiler檢查到.因此,儘可能地使用執行個體成員,而不要用靜態成員.

2. 在事件完成之後,將其設為引用 而且/或者(and / or) 將其remove掉,有助於減少記憶體使用量.

3. moduleLoader.unloadModule()會導致記憶體泄露,因此建議使用將moduleLoader.url=null.

4. module記憶體的釋放時間是不確定(並不是在unload的時候).

5. 使用debug版本的module會導致大量的記憶體泄露,不管其容器是否使用.

6. 將一個程式塊聲明為module,而不要將其聲明為application,並且設定各module專門為一個application進行最佳化,能大量節約記憶體.

7. 在適當的時候,為了記憶體可控,可強制使用垃圾收集器(garbageCollection).方法如下:
try {

import flash.net.LocalConnection;

var conn1:LocalConnection = new LocalConnection ();

var conn2:LocalConnection = new LocalConnection ();

conn1.connect("gc");

conn2.connect("gc");

}catch(e:Error){}

8. 使用release版的module swf.

9. 卸載debug版的flash player.

10. 安裝release版的flash player.

參考文檔:

1. Understanding garbage collection in Flash Player 9(http://www.adobe.com/devnet/flashplayer/articles/garbage_collection.html)

2. FLEX記憶體釋放最佳化原則(http://xinsync.xju.edu.cn/index.php/archives/1825)

3. Garbage Collection and Memory Leaks(http://blogs.adobe.com/aharui/2007/03/garbage_collection_and_memory.html)

4. memory leak when using TextInput and TextArea when click the keyboard(http://bugs.adobe.com/jira/browse/SDK-14781)

文章來源:http://binary-house.spaces.live.com/blog/cns!A2B1EFCF718495C4!269.entry

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.