앞선 포스팅에서 실행 메모리 영역에 대해서 말했습니다... 다른 말로 클로저 영역이라고 합니다.
js
a = function (b){
var c = 2;
var d = function (e){
var f;
alert(c);
}
d();
}
a();
as2
a = function (b){
var c = 2;
var d = function (e){
var f;
trace(c);
}
d();
}
a();
이런 함수를 만들면 둘 다 2 가 출력됩니다. alert 함수가 trace 함수로 바꼈을 뿐, 보시다시피 코드는 똑같습니다.
어떻게 2가 출력되었는지 살펴볼까요??
얼핏보면 a 란 함수를 실행하면 a 함수 내부에 선언된 d 함수가 실행됩니다.
d 함수 내부에는 c를 출력하여야 하는데, d 함수 내부에는 어디에도 c라는 변수가 없습니다... 인자에도 없고 함수 내부에 지역변수로 선언되어 있지도 않습니다.
그러면 d 함수가 실행되고 있는 영역인 a 함수를 찾아올라갑니다. 그 안에는 c와 d가 변수로 들어있고, b가 인자로 들어있지요... c를 찾았네요??? c란 변수가 참조하고 있는 2 값을 출력합니다...
d 함수를 실행하는 순간 vm에서는 앞서 말했듯 실행메모리 영역을 만들어냅니다.
e 가 들어오는 arguments 객체가 있고, var 로 선언된 f 가 있습니다. (사실 생략된 this도 설명해야 하는데, 이건 나중에...)
이런 메모리 테이블 공간이 만들어지는겁니다.
마찬가지로 a 함수에도 b로 들어온 arguments 객체가 있고, c, d 로 선언된 지역변수 메모리 테이블이 있겠죠...
어쨌든 d의 메모리 테이블이 만들어지고 나면 이제 한줄씩 한줄씩 작성되어져 있는 구문을 실행하는 겁니다
alert / trace 로 c를 출력해야 하는데 해당 메모리 테이블 공간에 c 가 없습니다...
그러면 이때 해당하는 변수가 정의되지 않았음을 나타내는 undefined 를 출력하는 것이 아니라 함수 d가 실행된 메모리 영역인 a 의 메모리 테이블을 검색합니다
앞선 포스팅에서 말했듯 저는 js를 사용해본 적이 거의 없기 때문에 잘 몰랐지만, as2는 사실 js를 그대로 본따 만든 언어입니다...
js의 window 가 바로 as2의 _global 이고, DOM 이 바로 MovieClip, TextField 입니다...
as2에서, new Array 는 가능하되... MovieClip은 new MovieClip 대신 attachMovie 를 써야하는 이유가 여기에 있는 겁니다. DOM 객체를 가져와서 사용할 뿐인거죠... 만들어서 쓰는 것이 아니고요
그러다 보니 as2도 js의 이원화된 메모리 관리를 그대로 따라갑니다...
2. 메모리 이원화
그럼 메모리 이원화에 대해 말해야겠군요...
js는 메모리 관리 영역이 두군데로 나뉩니다. 오브젝트(Object Class 를 말하는게 아닙니다) 영역과 실행 메모리 영역입니다...
프로그래밍을 해서 컴퓨터에서 실행을 하려면, 우리가 작성한 코드는 당연히 컴퓨터의 메모리 어딘가로 올라가야 합니다... 그래야 CPU에서 그걸 가지고 연산을 하겠죠...
우리가 작성한 코드... 그것을 하나의 오브젝트로 보고 js vm 에서 거대한 해시맵에 담아줍니다. 여기까지는 c 와 비슷하다면 비슷할겁니다.(전 c를 한번도 안해봤기 땜시 잘 모르겠지만...)
이것을 오브젝트 메모리 영역이라고 하겠습니다.
그럼 실행 메모리 영역은 무엇이냐...
코드란 것은 결국 동작시키기 위해 작성하는 것... 동작하지도 않을 코드는 존재하지 않겠죠...
앞에서 작성한 코드가 실행될 때... 즉, 함수가 실행될 때 메모리를 js vm에서 메모리를 새롭게 분배해 줍니다...
예를 들어, 함수 내에 var a = 1 라고 지역변수(일단은 이렇게 부르겠습니다)를 선언하면 1 이라는 Number 메모리를 새로 잡아주고 a 라는 변수에 참조시켜주는거죠
여기서 js가 c 같은 언어에 비해 느린 이유가 만들어집니다... c 는 동작시에 사용하게 될 메모리를 미리 개발자가 잡아놔야 합니다. 그러면 컴파일러에 의해 컴파일이 되면서 메모리를 정리(?)해주게 되고, 해당 포인터를 바로 사용하면 됩니다.
하지만 js는 컴파일이 없으니 실행되는 동안
vm이 알아서 그런 일을 다 해줘야 합니다...
게다가 알아서 생성해줬으니 알아서 지워도 줘야겠죠... 안그러면 메모리가 폭발할 테니까요... 바로 gc가 돌아야 합니다...
3. 요약
첫번째니 가볍게 정리를 하겠습니다.
1. as2 ≒ js
2. js는 메모리를 두가지로 관리한다. 오브젝트 영역과 실행 메모리 영역
글을 쓰는 2012년 1월을 기준으로 약 2년째 웹을 떠나있는 저로서는 사실 실무에서 js를 쓸 일이 전혀 없습니다.... (1년간 인터랙티브 미디어, 나머지는 스케일폼)
앞으로도 당분간은 쓸 예정이 없고요...
그 전에도 js는 ctrl +c, ctrl + v 로 쓰는 정도였을 뿐입니다... 단지 플래시앱의 테스트를 위해서였죠... 언어라는 생각도 하질 않았어요...
그러나 지금 js는 세상을 뒤엎고 있습니다... 구글이나 페북에서는 아이비리그 나온 친구들이 js를 다룹니다... 플래시는 그에 비해 저물어가니 유행을 타서 저도 포스팅을 시작.....한건 절대 아니고요...
작년 말부터 히카님의 지도(스터디이지만 지도라는 말이 어울립니다) 하에 S51 이란 js 스터디를 하고 있는데,
as2 == js 이고,
as3 은 js의 ecmascript3 스펙에 class 문법을 붙인
ecmascript4 스펙인 것을 다시 한번 몸소 깨닫고 있습니다...
스터디는 들은 후에 잊혀지는 법... 이걸 어따 써먹긴 해야겠는데...
같이 스케일폼 스터디를 하는 친구들에게 스케일폼4를 대비해 스케일폼에 맞는 as3 스터디를 시작하기로 했거든요... 그 초입단계로서 as2 와 as3를 좀 가르쳐야겠다고 생각을 했고...
그러면서 자연스레 js 문법을 가르치면 되겠다 싶었습니다...(헌데 문제는 더도 배우고 있는 중이라...)
앞선 두가지의 스터디의 일부로서 좀 정리가 필요하겠다 싶어서 카테고리를 하나 더 만듭니다...
아마도 다른 곳같은 실무에서의 js가 아닌, as2, as3 와 연결된 개념으로서의 포스팅이 될거라고 생각합니다.
첫째, http 통신을 할 수가 없다
둘째, 기본적인 키보드와 마우스 왼쪽 버튼 이벤트 말고도 여러 인터랙션이 있다.
세째, 가상폴더에서 실행된다...(udk 기준입니다... 다른 엔진도 그런지는...)...그렇기에 절대 경로를 찾기 어렵다.
이외에도 여러가지 제한이 있고, 반대로 추가적인 기능들이 있지만 일단 이렇습니다...
스케일폼에서 제공하는 scaleform.gfx.* 패키지를 보면 많은 클래스들이 있습니다. 이는 스케일폼의 여러 확장기능들을 이용하게 하기 위한 클래스들입니다.
다른 것은 둘째 치고 일단 Extensions.enabled 함수를 확인하셔야 합니다. (멤버변수가 아닌 set/get 함수입니다)
기본값은 false 이지만 이걸 true로 해두면 위에서 언급한 여러 확장기능들을 사용할 수 있게 됩니다.
아무튼 위에서 말한대로 스케일폼은 여러 세팅할 값들이 일반적인 플래시앱과는 꽤 다르게 해줘야 합니다
그런 세팅을 해야할 곳은 바로 시작점 클래스 입니다...
2. 시작점 클래스
플래시에서는 시작점 클래스란 것이 있습니다
바로 Document Class 인데, vm이 최초에 실행할 class 를 말하는겁니다.
엄밀히 말하자면 해당 class를 인스턴스로 만들어 stage에 addChild 하는 행위를 말합니다... 그렇게 인스턴스화 되는 과정에서 해당하는 class 의 생성자 함수가 실행되는 것이지요...
바로 앞선 구문에서
Extensions.enabled 에 true 값을 대입연산자인 = 로 줬습니다...
그런데 바로
Extensions.enabled 값이 true 인지를 판단한다라...?
이제
Extensions class를 다시 열어봐야할 시간이 됐습니다.
4.
Extensions class
// Enable/disable GFx extensions
static public function set enabled(value:Boolean) : void {}
static public function get enabled() : Boolean { return false; }
Extensions class의 enabled 함수가 구현되어 있는 모습입니다... 뭔가 이상하지 않나요??? 보통 set/get 함수를 만들면 다음과 같이 해야 하지 않나요?
static private var _enabled:Boolean = false;
static public function set enabled(value:Boolean) : void {
_enabled = value;
}
static public function get enabled() : Boolean { return
_enabled ; }
이렇게 말이죠... 그런데 Extensions class 안에는 _enabled 이 없습니다...
이녀석은 바로 scaleform 에 저장되는 값이기 때문입니다.
그렇다면 if (Extensions.enabled) 문의 비밀이 나옵니다.
Extensions.enabled = true;
if (Extensions.enabled) {
// 이 swf 가 돌아가는 vm은 scaleform 플레이어입니다
}
else{
// 이 swf 가 돌아가는 vm은 Flash 플레이어입니다
}
이 구문은 현재의 vm을 판단하는 부분입니다... 플래시 플레이어에는 _enabled 값이 저장될 곳이 없으니 언제나 get enabled() 가 false 만을 반환하기 때문이죠...
그런데 여기서 의문이 남습니다... 어차피 scaleform으로 돌릴 것을 만드는데, 왜 flash player 에서 돌리려고 하는건가요???
5. 그러니깐 그게 왜 필요한데... 어따 쓸거냐고...
스케일폼 플레이어는 디버깅에 제한을 받습니다... trace는 찍어주는데 break point 가 안먹어요...(제가 방법을 모르는 것인지는 모르겠습니다만...)
물론 하려고만 하면야 trace만으로도 잘 개발할 수 있습니다만... break point 가 좀 필요할 때가 있는 것도 사실이지요...
바로 디버깅의 편리함을 가져다 주기 위함이예요...
고작 브레이크포인트 디버깅 때문에 코드를 더럽히냐고 하실 수 있지만... 어차피 저 코드는 어떤 상황에서건 최초에 딱 한번만 실행됩니다. 런타임의 실행속도와 무관하지요...
이외에도 뭔가 다른 곳에 필요치 않을까요??? :^)
p.s. 사실 저는 다르게 만들어써요 ㅋㅋㅋ
p.s. 써놓고 보니깐 제목을 vm 판단하기...라고 지을걸 그랬나 싶다는... 이놈의 필력이란...
p.s. 12.02.15 추가
4.0.15 버전의 Extensions 클래스 안에 get isScaleform() : Boolean 과 isGFxPlayer : Boolean 속성이 생겼습니다.
이상하게 네이밍을 지은게 아니라면 이 속성으로 현재의 VM이 스케일폼인지 아닌지를 판단할 수 있을 듯 합니다
하지만 이중에서 하나는 부호입니다... 그러니 실제로는 52bit 만을 숫자에 활용합니다... 그런데 뭔가 이상하지 않나요? 프로그래밍인데 2의 승수인 32bit도 아니고, 64bit도 아닌 52bit 라니 말이죠...
이건 뭔가 이상합니다...
결론부터 말씀드리자면 사실 플래시의 Number는 64bit를 사용하고 있습니다...
실수를 메모리에 어떻게 표현할 것인가...
실수를 64bit라는 메모리에 표현하려면 어떻게 해야할까요... 간단하게 생각하면 1bit 부호 + 32bit 는 정수 + 31bit는 소수로 하면 될 듯 합니다...
그런데 그러고 보니 실수의 표현 범위가 너무나 작은겁니다... 그럼 1024bit쯤 할애하면 되잖아!!! 라고 말할 수도 있겠지만... 프로그래밍의 세계가 우리가 원하는 대로 해줄만큼 만만치가 않습니다.
그래서 생각하게 된 것이 실수를 정수처럼 일단 표현하고 그 뒤에 소수점을 찍자는 겁니다...
123456789 쓰고선 첫번째에 찍으면 .123456789 가 되고, 다른데 찍으면 123456.789 도 되는 것이죠...
뭔가 아이디어는 좋은 거 같은데 중요한 것이 하나 빠졌습니다... 소숫점을 몇번째에 찍을 것인가에 대한 데이터는 그럼 어디에 저장해야 하나요???
그래서 컴퓨터에서 사용하게 된 것이 이진법을 밑수로 한 부동소수점 표기법입니다...
(전 솔직히 이 용어를 누가 지었는지 모르겠지만 불만이 많습니다... 일반적으로 한국 사람이 "부동" 이란 자를 생각하면 "不動" 을 생각하지 않나요???)
실수의 부동소수점 표기방법
이진법을 밑수로 한 부동소수점 표기법...... 뭔가 되게 이름이 길지만 결국 다음과 같습니다...
0.4 = 0.8 * 2^(-1) 이 됩니다...
0.4 = 1.6 * 2^(-2) 도 물론 성립합니다...
이처럼 첫번째 숫자를 2(밑수) 밑의 수로 만들어 표현한 것을 정규화라고 합니다... 이걸 왜 하냐면... 무조건 1로 만들어준다는건 생략할 수도 있다는 말이고 그만큼 한자리를 더 표현할 수 있기 때문입니다...
1bit는 부호에 사용한다고 했습니다
52bit가 Number 의 범위라고 했지요... 자, 나머지 11bit는 바로 여기에 있습니다... 2의 - 승수입니다...
이에 따라 2진연산 오차도 생기는 것인데... 당연하게 52bit 이상을 실수에 쓰면 오차가 생기는 것이지요. 말했잖아요.... 52bit까지밖에 못쓴다니까요???
as3로 trace(1.3 - 1) 를 찍어보세요... 0.3을 기대하셨다면 안타깝다는 말씀밖에는 드릴 말이 없습니다...
제가 찍어보니 0.30000000000000004 가 나오는군요...
뭐 더 자세한건 위키백과를 찾아서 봐주세요... 이 포스팅이 이걸 얘기하려고 하는 것은 아니니까요...
부동소수점에 대한 글을 쓰려는게 아니라 통신에 대해 쓰려는 겁니다...
각 언어에서 지원하는 숫자타입
암튼 플래시에서는 저렇게 숫자를 사용합니다만... 다른 언어는 어떤가요...
전 플래시 말고는 배워본 적도 없는 비전공자이지만 여러 숫자타입이 있다는 것은 어깨너머 들어서 알고 있습니다... 그리고 같은 실수 표현법에도 플래시의 부동소수점 표기법에 따라 결과가 달라질 수 있습니다...
클라이언트에게 제가 인자를 던져달라고 할 때, 이렇게 말했습니다...
"숫자로 던져주세요..."
이제 게임회사 개발자로서는 이건 틀린 커뮤니케이션 방법이 된겁니다...
클라이언트가 52bit 이상의 숫자를 던져준다면??? 이정도까지 숫자를 쓸 일이 없다고요???
리니지 서비스한 지가 십수년이 흘렀죠??? 지금까지 모은 아덴이 있다면 얼마일 것 같나요???
만약 제가 누군가에게 우편으로 돈을 보냈는데, 플래시의 이진연산 오차로 잘못된 값을 보냈다면???
패치할때까지 게임서버 내리고... 버그를 찾아 찾아... 누구에게 책임이 돌아올까요???
단위가 매우 늘어날 수 있는 숫자타입은 차라리 String으로 던져주는 것이 안전합니다... 라고 결론을 내고 끝내고 싶은데...
그럼 뭘로 주고 받아야 하나요???
클라가 꼭 플래시처럼 문자열을 쓰란 법이 없습니다... 플래시는 문자가 아닙니다. 문자열입니다...
문자는 16bit 이고, 그에 따른 배열이란 말입니다.