ApplicationDomain과 runtime class loading
함수와 클래스의 정의는 어떻게 사용되는걸까?
먼저 메모리에서 일어나는 일을 생각해보자. 함수는 한 번만 정의하면 여러 번 호출할 수 있다. 실제 런타임 시, 메모리에 함수의 정의가 한 번만 저장되고 호출 시에는 이 저장된 메모리 영역을 호출하는 것으로 이해할 수 있다(실제로 그렇다)
그럼 클래스의 경우는 어떨까? 클래스도 메쏘드 부분은 함수와 마찬가지로 메모리에 한 번만 정의를 기록하고, 속성만 인스턴스별로 저장하는 것으로 생각할 수 있다. 즉 함수의 정의와 동일한 상태에서 마치 c의 구조체처럼 인스턴스별 속성을 저장하는 형태를 상상하면 쉬울 것이다. 실제로 초창기 c++컴파일러들은 어셈블리를 생성하지 않고 c로 번역하는 식으로 작동했는데 이 때 클래스를 구조체와 구조체의 포인터를 받는 함수로 번역해주는 형태였다.
어쨌든 요점은 함수, 클래스 할 것 없이 한 번만 메모리에 적재되고 런타임 시에는 이 메모리 영역을 참조해 실행한다는 점이다(참고로 as3에서 이러한 객체 정의를 기록하는 플레이어 수준의 객체는 trait로 상당히 메모리를 많이 잡아 먹는다)
함수와 클래스 정의를 너무 많이 하면 어떻게 되는걸까?
이러닝 프로젝트에서 흔하게 볼 수 있는 패턴인데, 클래스가 3천개쯤 나오는 경우다. 위에 설명한 대로 클래스 정의도 메모리를 상당히 사용하기 때문에 클래스 수가 너무 많아지면 메모리의 실행을 위한 공간은 줄고 클래스 정의가 다 차지하게 된다. 따라서 우리는 필요한 시점에 필요한 만큼만 클래스를 정의해서 사용해야한다.
함수와 클래스의 정의를 언제 메모리에 올리는걸까?
이건 참 중요한 질문이다. 함수와 클래스의 정의는 사실 이미 컴파일 타임에 완전히 검사하여 알고 있다. 프로그램이 실행되기 전에 미리 메모리에 함수, 클래스의 정의를 적재한 후 실행을 시작하는 방식이 기본이다. 약간의 예외가 있는데 동적정의를 허용하는 언어의 경우에는 실행도중에도 클래스나 함수의 정의를 할 수 있다. as3도 그러한 동적 클래스 및 동적 함수 리터럴을 제공한다. 이 방식을 사용하는 경우 컴파일러가 미리 메모리를 효율적으로 재편할 수 없기 때문에 실행능력이 매우 떨어지게 된다.
컴파일러가 미리 클래스와 함수의 정의를 알고 메모리에 이 정의를 적재한 후 실행하는 방식을 정적 클래스로딩 방식이라하며 c, c++ 등 초창기 고급언어가 이러한 방식을 사용한다. 이 방식의 장점은 컴파일 시 알 수 있는 구문만 메모리에 적재되므로 컴파일에 성공한 프로그램의 안정성이 매우 높다. 반대로 단점이라면 모든 클래스와 함수의 정의가 최초에 로딩되므로 초기 실행속도가 느리고 클래스와 함수의 정의가 많아지면 많아질수록 비대하게 메모리를 잡아먹게 된다.
이와 대비하여 자바 등의 후기 oop언어가 사용하는 동적 클래스로딩 방식이 있다. 동적 클래스로딩이란 클래스의 정의를 바로 메모리에 올리지 않고 그 클래스나 함수가 최초로 사용되는 시점에서 파일로 부터 읽어들여 메모리에 적재하는 방식을 뜻한다. 장단점도 이에 따른다. 장점은 실행시점에서 로딩하기 때문에 한 번에 로딩하는 렉이 없고, 메모리의 사용도 언제나 적절하게 유지된다. 반대로 초기화과정이 없으므로 동적클래스로딩에 실패할 수도 있는 등 안정성이 떨어지고 최초실행시마다 로딩하기 때문에 중간중간 속도가 느려지는 단점이 있다.
하지만 대세는 동적로딩이다. c++도 동적링킹을 지원한다(대표적으로 dll) 왜 동적로딩을 선호하는가?
메모리 사용이 효율적이기 때문이다.
예를 들어 a, b, c, d 클래스는 처음부터 필요하고 e, f, g 클래스는 중간에 잠깐 필요하며 h클래스는 끝에 가서 필요하다고 하자.
이론적으로 가장 이상적인 메모리 사용은 a, b, c, d는 최초에 로딩하여 끝까지 유지하고, e, f, g는 중간에 파일로부터 로딩하여 사용하다가 사용이 끝나면 메모리에서 정의를 제거한 뒤 마지막에 h가 필요한 시점에서 h를 파일로부터 로딩하여 사용하는 것이다.
이런 꿈같은 일이 가능한 것이냐? 그렇다면 어떻게 해야하는걸까?
as3에 대입하여 생각해보자.
최초 필요한 클래스의 정의가 메모리에 로딩되었다. 최초에 클래스정의가 로딩된 메모리 영역 – 이곳이 바로 기본 어플리케이션 영역이다. 영어로 해보면 System Application Domain 정도가 되지 않을까? 바로 그 말 그대로 ApplicationDomain 이란 객체가 존재하는 이유다. AS3는 최초 필요한 모든 클래스를 프로그램이 시작하자마자 메모리에 로딩하는데 바로 그 영역이 시스템 ApplicationDomain 이다. (Domain은 원래 영역이란 뜻)
이제 다른 swf를 로딩하는 경우를 생각해보자. 위의 예에서 e, f, g 클래스에 해당한다. e, f, g를 담고 있는 1.swf를 로딩하면 그 e, f, g 클래스의 정의를 메모리 어디에 넣을지 고민해야한다.
먼저 시스템 ApplicationDomain(이하 AD)에 넣는 경우를 보자.
시스템 AD의 경우는 프로그램이 종료될 때까지 영원히 해지될리가 없는 메모리 공간이다. 따라서 여기에 e, f, g 를 넣는다는 의미는 프로그램 종료 시까지 이 클래스 정의를 안고 가겠다는 뜻이다. 또한 시스템 AD에 이미 e가 있는 경우엔 1.swf 의 e는 시스템 AD에 덮어써지지 않는다. 당연한거지만 이미 시스템 AD에 있는 e를 통해 인스턴스를 만들었다면 e의 정의를 덮어쓰는 순간 엉망진창이 될 것이다. 이건 시스템 AD의 문제가 아니라 AD에 있는 클래스의 정의는 덮어쓸 수 없다 는 일반적인 문제다.
여하튼 중요한 점은 클래스의 정의를 시스템 AD에 넣으면 중간에 정의를 지우는건 불가능하다 란 것이다.
그럼 새로운 AD에 넣는 경우를 생각해보자.
요점은 아예 1.swf 를 위해 새로운 어플리케이션 공간을 만들어주자는 것이다. as3로 표현하면 new ApplicationDomain 정도 되겠다. 이렇게 하면 이 영역은 사용하다가 중간에 필요없어지면 지워버려도 시스템 본체에 영향이 없다.
참 클래스의 정의를 지우는 방법을 얘기 안해줬다. 클래스 정의가 더 이상 쓸모 없어지는 시점은 현재 그 클래스의 정의로 만들어진 인스턴스가 하나도 없고, 그 클래스가 static 메소드나 속성을 갖지 않으며, 그 클래스를 상속한 클래스의 인스턴스도 하나도 없어야하며, 현재 뿐만 아니라 앞으로도 코드 상에 이 클래스를 사용할 일이 없어야한다.
여러분은 이 조건을 수동으로 검사해서 언제 해지할지 결정할 수 있는가? 머 있을 수도 있겠다. 하지만 불가능하다고 많은 사람이 여기기 때문에 가비지컬렉터가 하기로 했다. 간단히 말해 ‘동적 클래스로딩 시스템 중 직접 클래스 정의를 해지하는 언어는 없다.‘ 전부 가비지컬렉터가 클래스정의를 제거한다.
언어의 일반론을 떠나서 as3에 사용할 수 있는 내용으로 가보자.
as3의 ApplicationDomain은 자바와 비슷하게 계층구조를 만들 수 있게 설계되었다(따라한거지..) 그래서 new ApplicationDomain( 부모도메인 ) 이란 방식으로 생성하는게 가능하다. 대체 어플리케이션영역을 상속하면 어떻게 되는거냐는 질문이 생긴다. 어플리케이션영역을 상속한다는 의미를 정확하게 이해할 필요가 있다.
1. 누가 이 상속받은 AD를 사용하는가?
로딩한 쪽 – 로딩한 쪽에서는 사실 new ApplicationDomain이나 new ApplicationDomain(부모도메인)이나 별반 상관없다. 어짜피 새영역이다.
로딩 당한 쪽 – 로딩 당한 쪽이 왜 영향을 받냐부터 생각하자. 로딩 당한 쪽이 a라는 클래스를 제공하는데, 그 a라는 클래스는 b라는 클래스를 소유하여 작동하도록 되어있다. b클래스가 1.swf측에도 있지만 로딩한 쪽(본체)에도 있는 경우 본체가 1.swf를 로딩한 후 a클래스를 사용하는 시점에서 부모도메인이 우선적으로 적용되어 본체측의 b클래스를 사용하게 된다. 해깔리니 두 번정도 읽어보자.
요점은 로딩 당한 쪽의 클래스를 사용하는건 결국 로딩한 본체다. 본체가 1.swf의 클래스를 호출하여 사용하는 시점에서 그 클래스가 본체의 클래스를 사용할 수 있나 없나를 결정한다.
이러한 상속체인은 꼭 본체와 로딩 당하는 쪽에서만 일어나는 것은 아니다. 예를들어 1.swf의 AD가 AD1이라하고 이후 2.swf를 로딩하는 시점에서 AD1을 상속하는 AD2를 2.swf에게 설정해줄 수 있다. 이렇게 되면 본체가 2.swf의 클래스를 사용하는 시점에서 같은 이름을 가진 클래스가 1.swf에 정의되어있다면 그 클래스가 2.swf의 클래스 내부에서 사용될 것이다. 왜 이런 복잡한 관계를 사용할까?
test.core 라는 패키지가 여러 패키지의 베이스가 되는 패키지라고 생각해보자. 그렇다면 core.swf에서 test.core패키지의 클래스를 로딩한 후 sample1.swf, sample2.swf…라는 식으로 로딩하는 시나리오를 생각해볼 수 있다. 이경우 sample1.swf의 AD가 core.swf의 AD를 상속하면 sample1.swf에 test.core클래스를 선언하지 않아도 사용가능한 상태가 된다.
즉 계층구조적인 로딩을 통해 공통부분을 한번만 로딩하게 할 수 있다는 뜻이다.
2. 같은 클래스란 대체 어디까지 같아야하는가?
위에서 한참 언급한 같은 클래스란 패키지+클래스명이 완전히 일치하는 경우다. 따라서 com.a 와 co.a 는 다른 클래스다. 이 경우 상속받은 도메인이라도 이름 문제가 생기지 않는다. 하지만 거꾸로 생각해보면 정말 com.bsidesoft.net.loader 라는 클래스가 1.swf에 있는 것과 2.swf에 있는게 다를 가능성이 있는가? 버전문제가 있을 수 있지만 그게 다른건 다른거 자체가 문제다. 즉 일반적인 경우에는 이름 충돌이 나지 않는다. 주로 이름 충돌이 나는건 package{ 로 시작하는 메인에 몰려있는 에셋클래스나 테스트 클래스 정도다.
3. 그럼 언제 상속받은 AD를 사용하라는 건가?
그거야 당연히 1.swf 가 로딩된 후 그 안에 있는 클래스들이 부모AD에 정의된 클래스를 참조하는 경우다. 이 경우에 상속받은 AD를 사용하면 동적으로 1.swf의 클래스 정의를 가비지컬렉터가 해지할 수 있을뿐만 아니라 사용시점에서는 부모AD의 클래스와 연결지어 사용할 수 있다.
그 외의 주제
동적 클래스로딩을 여기까지 따라와서 이해했다면 이 동적로딩이 주는 또다른 장점을 인식할 수 있다. 클래스의 정의를 특정시점에 특정파일로부터 읽어서 메모리에 적재하기 때문에 반드시 로컬에 있지 않은 객체라할지라도 원격에서 다운로드 받아 클래스를 적재할 수 있다는 점이다. 즉 이 특징이야말로 분산객체지향 모델을 만들어내는 근본적인 구조를 제공한다.
플래시에 국한하자면 [Embed..] 로 여러 자원을 모아서 swf를 생성하고 이 자원를 가져다쓰는 경우를 생각해볼 수 있다. 필요한 이미지, 사운드 등의 자료를 표준포멧이 아니라 swf에 넣음으로서 실행력향상, 용량감소 등의 잇점을 볼 수 있다.
이런 경우 클래스가 바이너리 데이터를 포함하는 형국이 되어 매우 큰 사이즈를 갖는다. 더욱 더 사용 후엔 가비지 컬렉팅 되길 바래야한다. 즉 새로운 도메인에 로드하는게 바람직하다.
어도비 공식문서를 바탕으로 다양한 실험을 한 분이 계시다. 트랙백으로 걸어둔다.
관련된 글:
감사합니다 ~
근데 아직 이해가 어려운 부분이 있어 개념적립이 필요할거 같아요 ㅎ
소규모 개발이라면 몰라도 큰 어플리케이션에선 필수적인 내용이니까..
flex프레임웍에선 프레임웍수준에서 해결해주고 있지만..
어려워도 반복해서 읽고 소화하면 도움이 될거야.
좋은 글입니다. 제 글보다. 조금더 풀어서 이해하기 쉽게 적으셨네요.
내용 정말 잘보고 갑니다.
^^ 감사합니당.
와.. 뭔가 알듯하면서 아직은 어렵네요 ^^;
좋은글 감사합니다~!
그러고보니 무비클립연구하던건 때려친겨?
Flex 모듈 프로그래밍의 기초 – Application domain의 이해 1부…
1. Application domain에 대해 1.1 모듈화와 모듈화에 따른 application domain의 역할 프로젝트를 하다 보면 모듈화를 할 필요가 생긴다. 모듈화는 하나의 메인 응용 프로그램에 모든 기능이 있는 대신, 관련된 기능을 떼어내어 모듈을 만들어 필요한 시점에 동적으로 불러 사용할 수 있도록 만드는 것을 의미한다. 가령 Flex로 만든 블로그가 있다고 가정하면. 블로그에는 글쓰기, 리스트, 방명록, 관리, 메뉴 등이 존재할 것…
Flex 모듈 프로그래밍의 기초 – Application domain의 이해 2부…
1. Application Domain 사용 예제 지난 호에서 우리는 Application domain에 대해서 알아보았다. 지금까지 설명한 내용을 확인하기 위해 몇가지 예제를 만들고자 한다. [그…..