Flash player 의 오랜 과제였던 메모리 관리 문제는 어떤 프로젝트를 진행하던지 간에 언제나 이슈로 대두 되었다.
특히나 Flex 내에서 모듈을 load하고 unload하는 과전에 있어서 메모리의 계속된 증가는
결국 사용자 PC의 브라우져가 과도한 메모리 점유로 인해 온갖 문제들을 야기 시켰는데
그것은 종국에 가서 클라이언트의 불만으로 이어지고
그런 불만을 해소하기 위해서 System.gc() 메서드나 LocalConnection 을 통한
강제 garbage collection을 해주고자 하였으나 근본적인 해결책은 되지 못했다.
한편 사람들은 메모리 문제에 대해서 removeListener를 통해 리스너를 삭제하는 방법들을
메모리 점유나 퍼포먼스에 대한 해결책으로 제시하고 있지만
문제는 무한이 늘어나는 인스턴스의 해결은 어찌 하느냐가 관건이었다.
전번 프로젝트를 통해 메모리를 줄여나가는 방법들에 대해서 여러가지로 연구하고
별의 별 방법들을 사용했고 시도했었다.
iframe을 통한 flash player의 브라우져 refresh는 Adobe사에서 권장하는 방법이었으나
다수의 Application의 생성이 불가피하고 rich internet 시장에 맞지 않는 작업들이라
클라이언트의 클래임을 설득하기 위한 회의는 연일 지속되어야만 했다.
게다가 refresh로 인해 Application의 다운로드 속도가 만족되어지지 않을 경우
RSL 방식이니 뭐니 하면서 Application 자체의 용량을 줄이기 위해 전쟁을 해야하는 상황들과 직면해야한다는 사실에는
변함이 없었다.
(그로인한 컴파일러 옵션값 조정에 몇 시간, 혹은 몇일의 시간을 날려먹었는지 모른다.)
프로젝트를 진행함에 있어서 가장 중요한것은 맨 마지막 산출물이 얼마나 rich한 작업이었는 지를
따지기 이전에 메모리의 양을 어찌 조절하느냐가 관건이 되었다.
앞뒤가 거꾸로 돌아가는 것이 아닌가 싶을정도로 고민과 번뇌로 코드를 들여다 봐야했고
메모리 점유율을 낮추기 위해 그리고 왜 낮춰지지 않는가에 대한 고민을 헤아릴 수 없이 해야만 했으며
생머리던 내 머리칼은 어찌나 쥐어뜯었는지 곱슬머리가 되어버렸다면 얼마나 많은 고민을 했을지 예상했으리라
그렇다면 왜 Flash player는 메모리를 낮추지 않을까?
왜 Flash player는 unload된 모듈에 대한 객체들을 지워주지 않을까에 대해 이해에 도움이 되기 위해서는
일단 Flash player 자체는 우리의 생각보다 멍청한 프로그램이고 뭐가 필요한 객체인지 아닌지에 대한
이해가 떨어지기 때문이라고 생각하면 속이 좀 편안해 질거다.
ActionScript에는 강한참조, 약한참조 가 있다는 사실은 조금만 공부해도 알 수 있는 내용이고
addEventListener 메서드로 이벤트를 등록할 때 useWeakReference 옵션 값을 true로 해줘서
약한참조로 만들어주면 gc가 돌때 등록된 이벤트를 같이 삭제한다고 이야기는 들었으나
이 약한참조라는게 어느 순간 목적 객체를 놓치는 경우가 종종 발생하여 문제는 계속해서 발생하게 된다.
(그 놈의 원인모를 문제는 다 여기서 나오는 거더라)
그렇다면 그냥 removeEventListener를 습관화 하는게 가장 좋은 방법이다.
묻지도 말고 따지지도 말고 그냥 무조건 remove시키는게 제일인것으로 결론이 났다.
그리고 가장 큰 문제인 ArrayCollection 의 강한참조가 문제다.
ArrayCollection은 정말 답이없는 객체다.
dataProvider로 DataGird 같은 List 객체나 Chart 객체에 Binding을 걸면 그것또한 낭패.
왜냐하면 ArrayCollection을 List 객체나 Chart객체 내부에선 dataProvider로 참조걸린 객체가 있다면
모듈 삭제시 인스턴스를 삭제 하지 않기때문이다.
한마디로 DataGrid가 삭제되도 내부의 데이터 값 자체는 삭제하지 못한다는 것이다.
이런 낭패가!
이벤트도 다 지웠겠다 UI객체들도 삭제했으니 당연히 메모리는 다시 원상 복구 되겠지!
하고 믿어 의심치 않고 있는 마당에 이런 뒤통수 맞는 경우가;;
Binding이라는게 쓸때는 참 편하고 좋다가도 이런 이유때문에 객체가 그대로 살아서 내 목을 조이고 있다고
생각하면 정말 믿는 도끼에 발등을 찍히는 기분이다.
그래서 UI객체가 삭제되는 시점을 틈타 FlexEvent.REMOVE 이벤트 발생시 객체들을 아래와 같이 삭제한다.
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]
private var tempAC:ArrayCollection;
override protected function createChildren():void
{
super.createChildren();
addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHanlder);
}
private function creationCompleteHandler(evnet:FlexEvent):void
{
removeEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
tempAC = new ArrayCollection([
{data1:"temp1", data2:"temp1"},
{data1:"temp2", data2:"temp2"},
{data1:"temp3", data2:"temp3"},
]);
addEventListener(FlexEvent.REMOVE, removeHandler);
}
private function removeHandler(event:FlexEvent):void
{
removeEventListener(FlexEvent.REMOVE, removeHandler);
Object(dg.dataProvider).removeAll();
tempAC.removeAll();
removeAllChildren();
}
]]>
<mx:DataGrid id="dg" dataProvider="{tempAC}">
<mx:columns>
<mx:DataGridColumn headerText="sample1" dataField="data1" />
<mx:DataGridColumn headerText="sample2" dataField="data2" />
</mx:columns>
</mx:DataGrid>
removeHandler부분을 잘보면 ArrayCollection 객체에 null로 삭제하는 것이 아니라 removeAll() 메서드로 삭제하고 있고 모든 이벤트 들은 사용이 종료되었을 때 그때 그때 삭제해주는 버릇이 중요하다.
그래야 쓸데없는 인스턴스를 줄일 수 있고 나중에 클라이언트와의 언쟁을 조금이라도 줄일 수 있게 되니 서로 간에 스트레스 없이 좋게좋게 끝낼 수 있을 것이다.






32085
30
59












댓글을 달아 주세요