1.02.2011

使用Apparat框架優化你的Flash動畫

誕生背景

Adobe的Flash編譯器(ASC, ActionScript Compiler)表現得實在太“昨天”了,加上Flash虛擬機在性能上還有很大的提升空間,Flash很多時候被當做玩具或者被戲稱為CPU hog。一般來說,我們很少會手去工優化一個SWF,大多數情況下,它都能良好地運行,但是當一個SWF文件尺寸過大導致加載時間過長或者代碼執行時間過長導致幀頻過低時,我們就需要考慮對SWF進行優化了,例如代碼的精簡,靜態資源(圖片、視頻等)的壓縮。但是手動優化產生的性能提升很是有限,更多的優化任務本應該交給編譯器來完成的,值得感激的是,Apparat框架可以幫助我們從手動優化的噩夢中解脫出來,不僅如此,任何未經過優化的SWF都能從中得到優化。Apparat的作者joa ebert在Flash性能優化領域有深刻見解,今年的FlashAndTheCity大會上,joa的出色工作為他贏得了“2010年最天才的Flash開發者”和“2010年最傑出的貢獻者”兩項大獎。

搭建環境

Apparat框架通過Scale寫成,在實踐它之前,需要先安裝Scala 2.8.0,Java 1.6,另外7-zip的安裝是可選的。搭建好這些基本的運行環境後(需要加入到PATH環境變量中),從Google Code可下載最新的安裝包(目前是1.0RC8)。下載後解壓到新的文件夾,其中包含的文件有:

Apparat提供了很多命令行工具,比如tdsi, stripper, reducer等等,還有一些非常特殊的ActionScript API(存在於SWC文件中)。接下來我們來看看Apparat是如何為Flash提速的。

優化字節碼

Apparat的核心功能是TAAS(Three Address ActionScript Compiler),TAAS不會改變任何一行ActionScript,它僅是使用普通的優化技術就能獲得可觀的性能提升。不同於Adobe的編譯器ASC,Apparat是對編譯過的SWF和SWC文件進行分析,再組織和再裝配。

Flash虛擬機AVM中的字節碼是基於堆棧的,這種結構難以再被優化,Apparat把基於堆棧的字節碼先轉換成CFG(Control Flow Graph),然後再通過CFG轉換成無堆棧的TAC(Three Address Code)碼, 即TAAS(Three Address ActionScript)。

有了TAC/TAAS, 就可以根據編譯器優化技術對Flash的字節碼進行再度優化了,例如inline expansion, copy propagation, constant folding, dead code elimination等等。

Apparat提供了幾個有用的SWC文件,它們擁有更加高效的API,甚至也包含了ActionScript還無法使用的Alchemy API。使用了這些API的SWF經過Apparat處理之後,執行效率要大大提升,其原理是Apparat對相應的代碼做了內聯(inline)優化。優化字節碼的命令格式是:

tdsi -i input.swf -o output.swf
去除debug信息

Stripper命令可以去除SWF中所有的debug信息,並且該移除方式是安全的,即不會產生side effect,比如代碼:

trace("the next element is: " + iter.next());

經過Stripper之後會變成:

(iter.next());

Stipper的命令格式是:

stripper -i input.swf -o output.swf
壓縮SWF

Reducer命令可以對嵌入在SWF中的PNG圖片進行JPEG有損壓縮,通常對PNG圖片進行100%品質的JPEG壓縮還能節省一定的文件存儲空間。該命令中有參數-q可以來設置壓縮質量,1.0表示最高的壓縮品質,0.0表示最低的壓縮品質。

reducer -i input.swf -o output.swf -q 0.8

如果Reducer通過環境變量能找到7-zip, Reducer將會利用7-zip做進一步的壓縮,那麼即使SWF中不包含圖片我們也能從此命令中獲得一些優化的余地,需要說明的是,目前此功能只能作用於SWF,對SWC文件無效。

Adobe使用Deflate壓縮算法對SWF進行壓縮,通過Reducer可以采用更先進的LZMA壓縮算法,由於Flash Player不認識LZMA,所以經過LZMA壓縮後的SWF被嵌入在另一個新的SWF中,新的SWF作為一個殼包含了原有的SWF以及一個運行時解碼器,目前這個解碼器大概在5KB左右。使用LZMA壓縮也可以看做是做了(較弱的)代碼混淆。

在使用Reducer命令時加上參數-l可以啟用LZMA壓縮:

reducer -i input.swf -o output.swf -l

除了壓縮圖片,Reducer還對代碼進行了合並,當鏈接外部的SWC時,每一個ABC文件都擁有一個常量池,Reducer能把所有的常量池合並成一個,並且它還對常量進行了排序,這樣頻繁使用的常量會具有更小的開銷。

經過我的測試與實踐,使用Reducer過程中有幾點需要注意:

  1. 使用JPEG壓縮後的Flash可能在低版本的Flash Player上呈現異樣的色調,所以壓縮後需要在低版本的Flash Player上進行檢測。
  2. 啟用LZMA很難達到文件尺寸的進一步減少,通常是增加了5KB,而且經過LZMA壓縮的SWF只能運行的Flash Player 10及其以上版本上。
其它

以上3個命令是主要是針對SWF,SWC做進一步的優化,包括程序執行時間的優化,圖片尺寸的優化,SWF存儲空間的優化,以及debug信息的清除。Apparat還包含其它一些有趣的功能,比如dump命令用來分析SWF中的標簽以及輸出UML圖,jitb命令可以把SWF轉換成Java字節碼從而運行在JVM上(還在完善當中)。

0 留言:

發佈留言

您使用留言則表示同意及遵守使用條款及守則

建議: 為方便留言回覆,請不要用匿名方式 留言。