Study/Actionscript 3.02010. 1. 19. 15:03
출처
http://www.adobe.com/kr/devnet/flashplayer/articles/garbage_collection.html#



Flash Player 9에서의 가비지 컬렉션 이해

Grant Skinner

Grant Skinner

CEO 겸 아키텍트 부문 책임자
gskinner.com*

작성일:
2007년 4월 9일
사용자 수준:
고급

한동안 ActionScript 3.0을 사용해본 결과 필자는 이제 그 기능에 완전히 매료되었습니다. 자체의 순수한 실행속도만으로도 많은 가능성을 제공합니다. E4X, 소켓, 바이트 배열, 새 디스플레이 목록 모델, RegEx 메서드, 형식화된이벤트 및 오류 모델, 기타 훌륭한 여러 기능을 맘껏 사용하며 상당히 흥미로운 혼합 툴을 만끽할 수 있습니다.

강한 힘에는 그만큼의 책임이 따른다는 말은 ActionScript 3.0에 딱 어울리는 말입니다. 완전히 새로워진 이컨트롤의 단점이 있다면 그것은 가비지 수집기가 언제 자동 정돈을 수행할지를 더 이상 예측할 수 없다는 것입니다. 즉,ActionScript 3.0을 사용하는 Flash 개발자는 가비지 수집기의 작동 방식과 효과적인 사용 방법에 대해 매우 잘알고 있어야 한다는 뜻입니다. 이러한 지식이 없으면 단순한 게임이나 애플리케이션을 만들더라도 마치 여과기처럼 모두 새나가는SWF가 만들어져 모든 시스템 리소스(CPU/RAM)를 독차지하고 시스템 오류, 심지어 컴퓨터를 강제로 다시 부팅해야 하는상황이 발생할 수 있습니다.

ActionScript 3.0에 맞게 코드를 최적화하는 방법을 이해하려면 우선 Flash Player 9에서 가비지수집기가 작동하는 방식을 이해해야 합니다. Flash에는 사용되지 않는 객체를 찾고 이를 제거하는 두 개의 프로세스가 있습니다.본 기술문서에서는 이 두 가지 기법에 대해 살펴보고 이들이 코드와 어떤 관계가 있는지에 대해 설명합니다.

본 기술문서 끝부분에서는 여기서 설명한 개념을 실제로 보여주는 Flash Player 9의 가비지 수집기 시뮬레이션이 제공됩니다.

가비지 수집기

가비지 수집기는 애플리케이션에서 더 이상 사용하지 않지만 객체에서 사용하고 있는 메모리의 할당을 해제하는 역할을 담당하는,배후에서 작동하는 프로세스입니다. 비활성 객체란 자신을 참조하는 기타 활성 객체가 없는 객체를 말합니다. 이를 이해하려면 기본유형이 아닌 유형(Boolean, String, Number, uint, int 이외의 유형)으로 작업할 때 항상 객체에 객체자체가 아니라 참조를 전달한다는 것을 깨닫는 것이 중요합니다. 변수를 삭제하면 객체 자체가 아니라 참조가 제거되는 것입니다.

다음 코드를 보면 이것을 쉽게 이해할 수 있습니다.

// create a new object, and put a reference to it in a:
var a:Object = {foo:"bar"}
// copy the reference to the object into b:
var b:Object = a;
// delete the reference to the object in a:
delete(a);
// check to see that the object is still referenced by b:
trace(b.foo); // traces "bar", so the object still exists.

위의 예제에서 코드를 업데이트하고 동시에 "b"를 삭제한다면 객체의 활성 참조가 없어져서 가비지 컬렉션용으로 비워지게됩니다. ActionScript 3.0 가비지 수집기는 활성 참조가 없는 객체를 찾기 위해 두 가지 방법, 즉 참조횟수(reference counting) 및 표시 회수(mark sweeping)를 사용합니다.

참조 횟수

참조 횟수는 활성 객체를 추적하는 가장 간단한 방법 중 하나이며 ActionScript 1.0부터 Flash에서사용되었습니다. 객체에 대한 참조를 만들면 참조 횟수가 증가합니다. 참조를 삭제하면 참조 횟수가 감소합니다. 객체의 참조 횟수가0이 되면 가비지 수집기에 의해 삭제됩니다.

예를 들면 다음과 같습니다.

var a:Object = {foo:"bar"}
// the object now has a reference count of 1 (a)
var b:Object = a;
// now it has a reference count of 2 (a & b)
delete(a);
// back to 1 (b)
delete(b);
// the reference count down is now 0
// the object can now be deallocated by the garbage collector

참조 횟수는 단순하면서 CPU 오버헤드를 크게 높이지 않기 때문에 대부분의 상황에 적합합니다. 그러나 순환 참조의 경우에는참조 횟수가 가비지 컬렉션을 위한 최적의 방법이 아닙니다. 순환 참조란 객체가 서로를 교차 참조하는 상황을 말합니다(다른 객체를통해 직접 또는 간접적으로). 애플리케이션이 해당 객체를 더 이상 사용하지 않더라도 참조 횟수가 0보다 큰 상태로 유지되므로가비지 수집기가 해당 객체를 제거하지 않습니다. 다음 코드는 이러한 경우를 보여줍니다.

var a:Object = {}
// create a second object, and reference the first object:
var b:Object = {foo:a};
// make the first object reference the second as well:
a.foo = b;
// delete both active application references:
delete(a);
delete(b);

위 코드에서는 활성 애플리케이션 참조 두 개가 모두 삭제되었습니다. 이제 애플리케이션에서는 이 두 객체에 전혀 액세스하지 않지만 두 객체는 서로를 참조하므로 참조 횟수가 1입니다. 이러한 상황은 훨씬 더 복잡해질 수 있으며(ac를 참조하고, c는 b를 참조하고, 또 b는 a를참조하는 등) 코드에서 다루기 힘들어질 수 있습니다. Flash Player 6과 7에는 XML 객체의 순환 참조와 관련된문제가 있었습니다. 자식과 부모 모두를 참조하는 각 XML 노드가 있어 이들의 할당이 해제되지 않는 문제였습니다. 다행히도Flash Player 8에는 표시(mark) 및 회수(sweep)라는 새로운 가비지 컬렉션 기법이 추가되었습니다.

표시-회수

ActionScript 3.0(및 Flash Player 8) 가비지 수집기에서 비활성 객체를 찾기 위해 사용되는 두 번째전략은 표시 및 회수라는 방법입니다. Flash Player는 애플리케이션의 루트 객체에서 시작하여(ActionScript3.0에서는 편리하게 "루트"라고 함) 그 내부의 모든 참조를 거치면서 발견되는 모든 객체를 표시합니다.

그런 다음 Flash Player는 표시된 각 객체를 반복합니다. Flash Player는 애플리케이션의 전체 객체 트리를검토할 때까지 이 동작을 재귀적으로 계속 수행하며, 활성 참조를 통해 도달할 수 있는 모든 것을 표시합니다. 이 프로세스가끝나면 Flash Player는 메모리에 있으면서 표시되지 않은 모든 객체는 더 이상 활성 참조가 없으므로 안전하게 할당 해제할수 있다고 가정할 수 있습니다. 그림 1은 이것의 작동 방식을 보여줍니다. 녹색 참조는 표시하는 동안 Flash Player를따라온 것이고, 녹색 객체는 표시된 것이고, 흰색 객체는 할당 해제될 것입니다.

Flash Player에서 표시 및 회수 방법을 통해 활성 참조가 없는 객체 식별

그림 1. Flash Player에서 표시 및 회수 방법을 통해 활성 참조가 없는 객체 식별

표시 및 회수는 매우 정확합니다. 그러나 Flash Player가 전체 객체 구조를 검토해야 하므로 CPU 사용 관점에서볼 때 이 프로세스에는 비용이 많이 듭니다. Flash Player 9에서는 표시 및 회수를 반복적으로 수행하고(동시에 모든프레임이 아니라 여러 프레임씩 나누어 프로세스 진행) 이 프로세스를 가끔 실행함으로써 이 비용을 줄입니다.

가비지 수집기의 지연 및 불확정성

Flash Player 9에서는 가비지 수집기의 작동이 지연됩니다. 이것은 매우 중요한 개념으로서 반드시 이해해야 합니다.모든 활성 참조가 삭제되더라도 객체가 즉시 제거되지 않고, 향후 불확정적인 시간에 제거됩니다(개발자 관점에서 볼 때). 가비지수집기는 일련의 추론을 사용하고 무엇보다도 RAM 할당 및 메모리 스택의 크기를 관찰하여 실행 시기를 결정합니다. 개발자입장에서는 비활성 객체가 언제 할당 해제될지 알 수 없다는 사실을 받아들여야 합니다. 또한 가비지 수집기가 비활성 객체의 할당을해제할 때까지 비활성 객체가 계속해서 실행될 수 있다는 점을 인식해야 합니다. 따라서 할당이 해제되기 전에는 코드도 계속실행되고(enterFrame 이벤트가 계속 발생), 사운드도 계속 재생되고, 로드도 계속 발생하며, 기타 이벤트도 계속 일어나게됩니다.

Flash Player의 가비지 수집기가 객체의 할당을 해제하는 시기를 개발자가 전혀 제어할 수 없다는 사실을 기억하는것이 매우 중요합니다. 개발자라면 게임과 애플리케이션을 완료할 때 그곳의 객체를 최대한 자신이 원하는 대로 제어하고 싶을것입니다. 이러한 프로세스의 관리 전략은 필자의 동료가 작성한 Flash Player 9의 리소스 관리 전략 기술문서에 소개되어 있습니다.

다음 가비지 컬렉션 시뮬레이션에서 전체 메모리의 톱니 모양을 살펴보십시오(그림 2 또는 아래 링크 클릭). 수집기가 회수를수행할 때 하강이 발생합니다. 차트를 자세히 보려면 클릭하십시오. 일시 중지하거나 다시 시작하려면 스페이스바를 누르고, 실행되는동안 메모리 사용 추세를 변경하려면 위/아래 화살표를 누르십시오.

가비지 컬렉션 시뮬레이션

그림 2. 가비지 컬렉션 시뮬레이션

다음 시뮬레이션에서는(그림 3 또는 아래 링크 클릭) 객체(둥근 직사각형) 및 객체에 대한 참조를 드래그하십시오. 그런다음 참조 횟수 또는 표시 및 회수를 실행하여 어떤 객체가 수집되는지 살펴보십시오. 객체에 있는 숫자는 해당 객체의 참조 횟수를나타냅니다.

가비지 컬렉션 시뮬레이션: 표시(mark) 및 회수(sweep)

그림 3.가비지 컬렉션 시뮬레이션: 표시(mark) 및 회수(sweep)

다음 단계로

가비지 컬렉션에 대한 이해는 Flash 프로젝트가 사용자의 컴퓨터에 최소한의 영향을 주며 실행될 수 있도록 보장하는 최적화된 코드를 작성하기 위한 가장 중요한 단계입니다. 필자의 동료가 작성한 기술문서, Flash Player 9의 리소스 관리 전략을 읽어보고 Flash 개발자 센터Flash Player 개발자 센터를 방문하십시오.

불충분한 참조에 대한 자세한 내용을 살펴보거나 필자가 작성한 보조 클래스를 다운로드하려면 필자의 블로그 gskinner.com을 방문하십시오.

저자 소개

Grant Skinner는 Flash 개발 및 컨설팅 업체인 gskinner.com*의CEO이자 아키텍트 부문의 책임자로 선도적인 신생 미디어 에이전시와 진취적인 기업 클라이언트와 함께 첨단 애플리케이션과 게임,멀티미디어 구성 요소를 제작하고 있습니다. 인터페이스 디자인, 유용성, 마케팅 및 비즈니스 로직에 코딩을 적용하는 전문성을 통해국제적인 명성을 얻고 있는 그는 FITC 2005의 Best Canadian Developer를 비롯하여 업계의 권위 있는 상을여러 번 수상했습니다. Grant는 gskinner.com/blog/*에서 블로그를 운영하며 incomplet.org*에 그의 실험적 작품을 전시하고 있습니다.


Posted by chacolina