2009年11月11日 星期三

Paper Vision 3D 正確 destory 物件的方法

由於 AS3 有 garbage collection 的機制,這樣的機制有好有壞,但千萬別以為有 garbage collection 就不用去在意 memory 的議題,因為不管 garbage collection 運作的原理是什麼,它總還是有一套運作的規則,不去依循這個規則的話,仍然會造成 memory leaks。

garbage collection 主要的扮演角色的是在程式背後的「管理程式」,記錄、管理使用者(這裡指程式設計師) 記憶體的使用狀況,它底層的意義就是在記錄某段記憶體是不是有物件(指標、參考…)指向它,若沒的話,便能進行釋放。

可以想像的到,一個環狀的參考一定會造成 garbage collection 的困擾,因此,在具備 garbage collection 的系統下寫程式,有些地方便要特別注意,才不會造成問題。

以前在 C++,常常會使用指標將自己 allocate 到的 memory 記錄下來,以便在物件 destroy 時一併釋放,但在 garbage collection 系統,這樣的習慣卻會造成「過多的」或「意外的」參考到了沒用到的記憶體,反而造成 garbage collection 無法正確運作。

因此在寫 AS3 時,儘量在要用到時才去 new 一個物件,而不需要在初始化時就把一切 new 出來放在私有變數裡去作準備,當然,這也不是通則,期待更好的 garbage collection 系統出現。

回歸正題,Paper Vision 3D 物件的創建跟刪除便出現了類似上述的問題,當你用「動態」的產生物件 (譬如 sphere 或 cube) 時,由於物件需要參考到 Material 材質,而材質又會記錄著使用這個 Material 的物件 list,於是當你刪除物件( 從 scene 移除並設為 null ) 卻發現 garbage collection 起不了作用,memory 依然被佔用住,這樣的 memory leaks 造成的後果會非常嚴重,memory 用量會不斷攀升,最後效能直線下降。

在 Paper Vision 3D 團隊還沒修正這段(bug?)或 改用更好的作法之前…
解決方法:

        private function destory3DObject():void
        {
            var objArray:Array = new Array();
            var obj:DisplayObject3D;
            for each ( obj in this.scene.objects )
                objArray.push(obj);
           
            for ( obj=objArray.pop(); obj; obj=objArray.pop() )
            {
                var mmArray:Array = new Array();
                var mm:MaterialObject3D;
                for each ( mm in obj.materials )
                    mmArray.push(mm);

                for ( mm=mmArray.pop(); mm; mm=mmArray.pop() )
                {
                    mm.interactive = false;
                    mm.unregisterObject(obj);
                    obj.materials.removeMaterial(mm);
                    mm.destroy();
                }
                obj.materials = null;
                //obj.material.animated = false;
                obj.material.interactive = false;
                obj.material.unregisterObject(obj);               
                this.scene.removeChild( obj );
                obj.material.destroy()
                obj.material = null;
            }
        }

 每個步驟的先後順序很重要,次序相反有可能還是沒清楚跟 garbage collection 系統交待好你不要這段 memory 了,你會發現,最後參考到這段 memory 的會是區域變數 var obj,如此才能保證在離開 scope 後沒有任何參考指標與該物件有關聯。

這個函式是一次清除所有的  DisplayObject3D物件,若只想清除物定物件,那可以使用 array 來裝你的 DisplayObject3D 物件即可,程式雷同。

所以其實 garbage collection 好壞見仁見智吧,好像只不過換了方式去管理你創出來的物件/記憶體罷了,恐怕還是需要瞭解黑箱下的作業方式,才能真正去掌握你所有的資源。

沒有留言:

更高效處理 micro second 的方式

更高效處理 micro second 的方式…  以 STM32 為例… __IO unsigned long sys_tick = 0; void SysTick_Handler(void) {     HAL_IncTick();     sys_tick += (SysTi...