참고 : Adobe Flex3 실전 트레이닝 북, 해외 블로그, 국내 블로그
이 글은 어도비리아에 기술문서로 제출 되었으며, 동일한 내용을 어도비리아에서 볼 수 있습니다.


-2부 프로파일링-
<목차>
1. 프로파일링이란?
2. 가비지 콜렉션
2-1. 레퍼런스 카운팅
2-2. 마크앤스윕
3. Flex Profiling perspective
3-1. 메모리 프로파일링
3-1-1. Profile 뷰
3-1-2. Memory Usage 뷰
3-1-3. Live Objects 뷰
3-1-4. Memory Snapshot 뷰
3-1-5. Object References 뷰
3-1-6. Loitering Objects 뷰
3-1-7. Allocation Trace 뷰
3-1-8. Object Statistics 뷰
3-2. 퍼포먼스 프로파일링
3-2-1. Performance Profile 뷰
3-2-2. Method Statistics 뷰
4. 맺음말


1. 프로파일링 이란?
애플리케이션을 개발하고 실행하게 되면 알 수 없는 원인에 의해 느려지거나 심지어 멈추는 경우가 종종 발생한다. 디버깅만으로는 이런 알 수 없는 원인을 찾아내기란 쉽지 않다. 이런 경우 애플리케이션의 성능측정을 통해 어느 부분에서 어떤 문제가 발생하는지를 찾아낼 수 있다. 성능측정을 전문적인 용어로 프로파일링 이라고 한다.
프로파일링은 디버깅과 더불어 소프트웨어 품질 향상에 도움을 준다.

우리는 Flex Builder3 Professional(이하 플렉스빌더) 에서 제공하는 프로파일링 기능을 이용할 것이다.
(Flex Builder Standard 버전은 프로파일링 기능을 제공하지 않는다.)
플렉스빌더에서 프로파일링을 하기전 플래시 플레이어의 가비지 콜렉션에 대한 이해가 필요하다.
따라서 먼저 가비지 콜렉션에 대해 알아보겠다.


2. 가비지 콜렉션
가비지 콜렉션이란, 플래시 플레이어의 숨겨진 프로세스인 "가비지 콜렉터"에 의해서 참조 되지 않는 객체들을 메모리에서 해제 하는 것을 말한다. 참조 되지 않는 객체가 있다고 해서
가비지 콜렉션이 무조건 수행되는건 아니다. 가비지 콜렉션이 언제 어느 시점에서 일어나는지 정확하게 알 수는 없지만 짐작할 수 있는 시점은 현재 애플리케이션이 플래시 플레이어가 OS로부터 빌려온 메모리 보다 더 많은 메모리를 요구할 때 이다.

가비지 콜렉터는 객체가 더 이상 참조되지 않는지 확인하기 위해 레퍼런스 카운팅마크앤스윕 이라는 두 가지 절차를 따른 후 가비지 콜렉션을 수행한다. 이 두 가지 절차를 이해하는 것은 플렉스 프로파일링 기능을 이용하는데 도움을 줄 것이고 메모리를 효율적으로 이용하는 애플리케이션을 작성하도록 도움을 줄 것이다.

그럼 가비지 콜렉션을 위한 두 가지 절차에 대해 알아보자.


2-1. 레퍼런스 카운팅
레퍼런스 카운팅은 ActionScript 1.0 때 부터 사용되어 왔으며, 객체가 가비지 콜렉션의 대상인지 확인하는 가장 쉽고 빠른 방법이다. 어떤 객체를 생성하고
참조값(해당 객체의 메모리 주소 값)을 레퍼런스(참조변수)에 할당하면 레퍼런스 카운트가 1 증가한다. 이 객체의 참조값을 또 다른 레퍼런스에 할당하면 레퍼런스 카운트가 1 증가되어 총 2가 된다. 만약 두개의 레퍼런스중 하나의 레퍼런스에 null을 할당하게 되면 레퍼런스 카운트는 1이 감소하며, 남은 하나의 레퍼런스 마저 null을 할당하면 레퍼런스 카운트는 0이 되어 버린다. 가비지 콜렉터는 레퍼런스 카운트가 0인 것들을 가비지 콜렉션의 대상으로 삼는다.

다음 예제를 보면 쉽게 이해할 수 있을 것이다.


위 예제에서 생성된 Object는 레퍼런스 카운트가 0이기 때문에 가비지 콜렉션의 대상이 된다.
하지만 레퍼런스 카운팅 만으로는 상호참조에 대한 문제를 해결할 수 없다.

상호참조가 무엇인지 다음 예제를 통해 살펴보자.


위 예제에서 생성된 두개의 Object는 obj.foo와 obj2.foo 에서 상호참조 되고 있다.
obj와 obj2에 null을 할당하더라도 이 두개 Object의 레퍼런스 카운트는 결코 0이 될 수 없다.
이런 상황은 매우 빈번하게 일어나며 더욱 복잡해질 수 있다. 플래시 플레이어7 까지는 XML 객체에서 노드들의 상호참조 때문에 이슈가 되기도 했는데, 다행히 플래시 플레이어8에서 마크앤스윕 이라는 새로운 방법이 등장해 이 문제를 해결하고 있다.


2-2. 마크앤스윕
플래시 플레이어(버전 8이상) 는 루트객체(Application 자체 또는 메인MXML) 부터 시작해서 루트객체가 참조하는 객체들과 그 객체들(참조 당하는 객체들)이 참조하는 객체들을 마킹한다. 여기서 마킹의 의미는 객체가 가비지 콜렉션의 대상이 되지 않게 하기 위해 점 찍어두는 것이다. 이 처럼 플래시 플레이어는 애플리케이션의 모든 객체트리를 돌며 참조되고 있는 객체들을 마킹한다. 마킹된 객체들은 레퍼런스 카운트가 무조건 1이상이기 때문에 결코 가비지 컬렉션의 대상이 되지 않는다. 반면 마킹되지 않은 객체들은 가비지 컬렉션의 대상이 된다. 마킹되지 않은 객체는 레퍼런스 카운트가 0일거라고 생각할 수 있지만 그렇지 않다. 플래시 플레이어는 오직 루트객체 까지 연결된 객체만 마킹하므로, 루트객체 까지 연결되지 않은 상호참조 객체들은 마킹되지 않는다. 따라서 상호참조 객체들은 레퍼런스 카운트가 1이상이라도 루트객체에 연결되어 있지 않으면 가비지 콜렉션의 대상이 된다.

다음 그림을 통해 마킹된 객체와 마킹되지 않은 객체들을 파악해보자.


(위 그림은 어도비에서 제공하는 가비지 콜렉터 시뮬레이션이다. http://www.adobe.com/devnet/flashplayer/articles/garbage_collection/example2.html 에서 직접 시뮬레이션 해볼 수 있다.)

위 그림에서 초록색은 루트객체에 연결된 마킹된 객체들이고 빨간색은 상호참조로 인해 레퍼런스 카운트가 각각 1 이지만 루트객체에 연결되지 않았기 때문에 가비지 콜렉션이 수행되면 빨간색 객체들은 메모리에서 제거될 것이다.

지금까지 플래시 플레이어에서 메모리가 어떻게 관리되는지 가비지 콜렉션이 언제 수행되는지 그리고 가비지 콜렉션이 수행될 때 거치는 두가지 과정에 대해 알아봤다. 이러한 밑 바탕이 되는 지식과 함께 본격적으로 플렉스 프로파일링을 시작해 보겠다.


3. Flex Profiling perspective
Flex Profiling perspective 는 플렉스빌더에서 제공하는 프로파일링 관련 도구들을 모아놓은 작업 환경이다.
이 작업 환경에서 실시간으로 애플리케이션이 사용하는 메모리를 비롯해 생성된 객체들의 수를 확인할 수 있는 메모리 프로파일링과, 함수 수행 시간을 확인할 수 있는 퍼포먼스 프로파일링을 할 수 있다.


3-1. 메모리 프로파일링

메모리 프로파일링은 일반적으로 애플리케이션의 메모리가 계속 증가 할 때 이용한다.
메모리가 계속 증가하는 이유는 더 이상 사용되지 않는 객체들이 어디선가 참조되고 있어서 가비지 콜렉터가 제거하지 못하기 때문이다. 이러한 현상을 보다 전문적인 용어로 메모리 누수(memory leak) 라고 부른다.

메모리 프로파일링은 메모리 누수를 찾을수 있을뿐만 아니라, 어디서 어떤 객체가 생성되고 있으며 객체들이 얼마 만큼의 메모리를 차지하고 있는지 알 수 있다. 또한 특정한 두개의 서로 다른 시점의 메모리 상태를 저장하고 이를 비교분석 할 수도 있다.

먼저 정상적인 애플리케이션을 통해 플렉스빌더의 프로파일링 도구를 살펴보자.
아래의 코드를 프로파일링 모드로 실행한다. (디버그 실행버튼 바로 오른쪽 버튼)


프로파일링 실행버튼을 누르면 다음과 같은 창이 나타난다.


위 창은 프로파일링 옵션을 묻는 창이다. 메모리 프로파일링의 경우 두가지 옵션이 더 존재하는데 Watch live memory data는 실시간으로 현재 활동중인 객체와 메모리 크기를 감지하고 지금까지 생성되었던 객체와 메모리의 크기를 알 수 있는 옵션이며, Generate object allocation stack traces는 특정한 두 시점 사이에서 호출된 메소드와 그 메소드에서 사용했던 메모리 크기를 알 수 있는 옵션이다. 모든 체크박스를 선택하게 될 경우 프로파일링 데이터 수집을 그 만큼 더 많이 하게 되기 때문에 애플리케이션의 속도가 느려진다. 지금은 위 그림처럼 메모리 프로파링일 항목만(하위 두개의 옵션 포함) 체크하고 Resume 버튼으로 프로파일링을 시작해보자.

프로파일링이 시작되면 플렉스빌더는 프로파일링 모드로 전환되고 다음 그림처럼 보일 것이다.


①번 영역은 프로파일링 목록과 프로파일링 실행을 제어할 수 있는 [Profile 뷰] 이다.
②번 영역은 현재 메모리 상황을 그래프로 표현하는 [Memory Usage 뷰] 이다.
③번 영역은 실시간으로 메모리에 존재하는 객체들을 볼 수 있는 [Live Objects 뷰] 이다.

그럼 먼저 프로파일링을 시작했을 때 기본적으로 보여지는 위 세가지 뷰에 대해 자세히 알아보겠다.


3-1-1. Profile 뷰
프로파일링이 시작된 이후에, 프로파일링을 일시중지 하고 다시 시작 하는 등 실행을 제어 하거나, 메모리와 퍼포먼스 분석을 위한 스냅샷 저장을 할 때 [Profile 뷰] 이용한다. [Profile 뷰] 는 프로파일링 실행을 제어할 수 있는 컨트롤 부분과 프로파일링이 진행중 이거나 이미 중단된 애플리케이션과 스냅샷의 목록이 나타나는 부분이 있다. 애플리케이션 목록 중 하나를 선택하고 수행하길 원하는 버튼을 클릭함으로써 프로파일링을 제어하게 된다. 그럼 실행을 제어하는 컨트롤 부분의 버튼들이 어떤 기능을 하는지 알아 보도록 하겠다.

Resume
일시 정지된 애플리케이션과 함께 프로파일링을 다시 계속한다.

Suspend
애플리케이션과 함께 프로파일링을 일시 정지한다.

Terminate
프로파일링을 종료 한다. 애플리케이션(브라우저)는 종료되지 않는다.

Run Garbage Collector
강제적으로 가비지 콜렉션 수행한다. 이 버튼을 누르면 [Memory Usage 뷰] 에서 가비지 콜렉션이 수행된 것을 알 수 있다.

Take Memory Snapshot
현재 실행중인 애플리케이션의 메모리 상황을 저장하고, [Profile 뷰]의 선택된 애플리케이션 하위로 메모리 스냅샷 항목이 추가된다. 이 버튼을 누르면 가장 먼저 가비지 콜렉션을 수행한 뒤 메모리 상황을 저장한다. 가비지 콜렉션이 먼저 수행되는 이유는 가비지 객체들이 메모리 상황을 분석하는데 있어서 잘못된 정보로 활용되기 때문이다. 메모리 스냅샷은 1개 이상 저장할 수 있고, 저장된 스냅샷 목록중 하나를 더블클릭 했을 때 열리는 [Memory Snapshot 뷰] 를 이용해 그 당시 메모리 상황을 분석할 수 있다. 또한 저장된 스냅샷 목록 중 두개의 스냅샷을 한 쌍으로하여 앞으로 나오게 될 두 시점 사이의 비교 기능을 이용할 수 있다. 자세한 내용은
3-1-4. Memory Snapshot 뷰, 3-1-6. Loitering Objects 뷰, 3-1-7. Allocation Trace 뷰 이 세 파트에 걸쳐서 다루겠다.

Find Loitering Objects
이 버튼은 메모리 스냅샷 목록 중 두개를 선택 했을 때 작동 된다. 이 버튼은 선택된 두 메모리 스냅샷을 비교하여 두 시점 사이에서 생성된 객체들을 확인할 수 있는 [Loitering Objects 뷰]를 연다. 자세한 내용은
3-1-6.
Loitering Objects 뷰
파트에서 다루겠다.

View Allocation Trace
이 버튼은 프로파일링을 시작할 대 실행 옵션을 묻는 창에서 Generate object allocation stack traces 항목을 체크하고, 메모리 스냅샷 목록 중 두개를 선택 했을 때 작동 된다. 이 버튼은 선택된 두 메모리 스냅샷을 비교하여 두 시점 사이에서 수행된 메소드들을 확인할 수 있는 [Allocation Trace 뷰]를 연다. 자세한 내용   3-1-7. Allocation Trace 뷰 파트에서 다루겠다.

Reset Performance Data
현재까지 플렉스빌더가 수집한 퍼포먼스 데이터를 초기화 한다. 플렉스빌더는 이 버튼이 눌린 시점으로 하여 퍼포먼스 데이터를 새로 수집하게 된다.

Capture Performance Profile
프로파일링이 시작된 이후 또는 퍼포먼스 데이터가 초기화된 시점부터 현재까지 수집한 퍼포먼스 데이터를 저장하고, [Profile 뷰]의 선택된 애플리케이션 하위로 퍼포먼스 스냅샷 항목을 추가한다. 추가된 퍼포먼스 스냅샷 항목을 더블클릭 하면 성능에 관련된 정보를 보여주는 [Performance Profile 뷰]가 열린다. 자세한 내용은 3-2. 퍼포먼스 프로파일링 파트에서 다루겠다.

Delete
선택된 스냅샷 항목 또는 프로파일링이 종료되고 선택된 애플리케이션을 목록에서 제거한다.


3-1-2. Memory Usage 뷰
만약 여러분의 애플리케이션에서 메모리가 정상적인지 확인하고 싶다면 가장 먼저 [Memory Usage 뷰]를 확인하라. [Memory Usage 뷰]를 통해 플래시 플레이어의 메모리 상황을 한눈에 파악할 수 있기 때문에 메모리 누수가 발생하는지 가장 쉽고 빠르게 알 수 있는 도구이다.


위 그림에서 빨간색 라인은 애플리케이션이 시작된 이후로 가장 많은 메모리를 사용했던 양을 나타내고, 파란색 라인은 현재 사용중인 메모리 양을 나타낸다. 위 그래프는 매우 정상적인 흐름의 톱니 패턴을 띄고 있다. 이 톱니 패턴은 앞서 설명 했듯이 애플리케이션이 플래시 플레이어가 OS로 부터 빌려온 메모리 보다 더 많은 메모리를 요구할 때 가비지 콜렉션이 수행된 흔적이다.


3-1-3. Live Objects 뷰
애플리케이션에 존재하는 객체들을 실시간으로 확인하고 싶을 때 [Live Objects 뷰]를 이용한다. 이 뷰는 프로파일링이 진행되는 동안 애플리케이션에서 실시간으로 생성되는 객체와 그 객체가 얼마나 많은 메모리를 사용하는지 보여준다. 또한, 그것들에 대한 누적된 수치도 함께 보여준다.


위 그림에서 알 수 있듯이 [Live Objects 뷰]에는 6개의 컬럼이 존재한다. 이 중 Class, Package 컬럼은 궂이 설명하지 않아도 어떤 컬럼인지 알 수 있을 것이다. 그 두개를 제외한 나머지 컬럼들에 대해 알아보자.
Cumulative Instances
프로파일링이 시작된 이후로 생성된 객체의 누적 합계이다.

Instances
현재 메모리에 존재하는 객체의 수이다.

Cumulative Memory
프로파일링이 시작된 이후로 생성된 객체가 사용했던 메모리 양의 누적 합계이다.

Memory
현재 메모리에 존재하는 객체가 사용중인 메모리 양이다.

위 그림에서 처럼 Package 컬럼 값이 없거나 그 외에 생소한 값을 가진 항목들은 우리가 만든 애플리케이션 단계의 정보가 아니기 때문에 그다지 유용한 정보가 되지 못한다. 지금 우리에게 필요한 정보는 예제 코드에서 1초마다 100개씩 생성되고 있는 DataGrid 객체에 대한 정보일 것이다. 하지만 기본적으로 적용된 필터 때문에 우리에게 필요한 DataGrid 객체에 대한 정보를 볼 수 없기 때문에 필터를 수정해야 한다.

먼저 위 그림의 우측 상단의 빨간색 마크된 부분의 세번째 아이콘을 누르면 Filters 창이 나타나는데, Inclusion filters와 Exclustion filters를 다음과 같이 변경하자. 그러면 필터의 포함 항목과 제외 항목을 통해 적절하게 필터링된 객체들이 보여질 것이다.


DataGrid 클래스의 패키지인 mx.controls.* 패키지를 포함 시켰다면 다음과 같이 [Live Objects 뷰]에 DataGrid 하나만 나타날 것이다.


위 그림에서 처럼 DataGrid 객체가 지금까지 어마어마하게 생성 되었으며, 현재 메모리에서 존재하는 객체의 수를 비롯해 사용중인 메모리 양도 쉽게 알 수 있다. 이처럼 [Live Objects 뷰]를 통해 실시간으로 생성되거나 소멸되는 객체들 뿐만 아니라, 누적된 수치까지 확인함으로써 애플리케이션의 전반적인 메모리 상황을 알 수 있고, 이러한 정보는 여러분의 애플리케이션을 깊게 이해하는데 도움이 될 것이다.


※코드 변경하기
지금까지 프로파일링이 시작되었을 때 구성되는 기본적인 뷰들에 대해 알아봤다. 이제 예제 코드를 변경한 후 [Memory Usage 뷰]를 통해 메모리 누수를 확인할 것이다. 그리고 앞으로 나오게 될 [Memory Snapshot 뷰] 와 [Loitering Objects 뷰] 그리고 [Allocation Trace 뷰]를 이용해 어디에서 메모리 누수가 발생하는지 확인할 것이다. 변경된 코드는 다음과 같다.

코드를 변경했다면 프로파일링을 시작하고 [Memory Usage 뷰]를 관찰해 보자. 다음 그림처럼 메모리가 계속 상승하는 그래프를 볼 수 있을 것이다. 이렇게 메모리가 계속 상승하는 이유는 가비지 콜렉션이 수행될 때 메모리에서 제거 되어야할 객체들이 어디선가 계속 참조되고 있기 때문이다.


변경된 예제코드에서 직접 메모리 누수 부분을 찾을 수 있지만 우리는 그 사실을 모른다고 가정하고 메모리 프로파일링을 통해 어디에서 메모리 누수가 발생하는데 찾아볼 것이다.

3-1-4. Memory Snapshot 뷰
여러분이 과거 특정한 시점에 저장했던 메모리 상황을 알고 싶을 때 [Memory Snapshot 뷰]를 이용한다. 이 뷰는 특정한 시점의 메모리 상황을 보여 주는 것이기 때문에 [Live Objects 뷰] 처럼 메모리 상황을 업데이트 하지 않고, 오직 해당 시점의 메모리 상황만 보여주는 정적인 뷰이다. [Profile 뷰]에서 저장된 메모리 스냅샷 항목을 더블클릭 하면 이 뷰를 열 수 있다.

이제 위 예제코드의 문제점을 찾아보자. [Memory Usage 뷰] 에서 메모리 누수를 포착 했다면 가장 먼저 [Live Objects 뷰]를 통해서 어떤 객체가 메모리에서 계속 증가하는지 발견해야 한다. 여러분은 이미 [Live Objects 뷰]에 대한 사용법을 알고 있고, 직접 확인해보면 DataGrid 객체가 계속 증가하는 것을 확인할 수 있을 것이다. 확인 했다면 Take Memory Snapshot 버튼으로 메모리 스냅샷을 만들고, 추가된 메모리 스냅샷을 더블클릭 하여 [Memory Snapshot 뷰]를 열어보자. [Memory Snapshot 뷰]를 열었다면 다음 그림처럼 DataGrid 객체만 나오도록 앞서 배운 필터를 설정해보자.


[Memory Snapshot 뷰]에서 제공하는 컬럼들은 앞서 배운 [Live Objects 뷰]에 이미 있는 것들이다. 우리는 현재까지 [Memory Usage 뷰]를 통해 메모리 누수를 발견하고 [Live Objects 뷰]를 통해 DataGrid 가 계속 생성되는 것을 확인했다. 이제는 그 문제의 DataGrid 객체가 과연 어디에서 생성되는지 알아야할 때 이다. 위 그림에서 알 수 있듯이 [Memory Snapshot 뷰] 자체만으로는 DataGrid가 어디서 생성되는지 알 수가 없다. 하지만 이 뷰에서 특정 로우를 더블클릭 하거나, 특정 로우를 선택한 상태에서 우측상단 빨간색 박스 부분의 첫번째 아이콘을 누르면 객체가 어디에서 생성되었는지 알려주는 [Object References 뷰]를 열 수 있다. 자세한 내용은 바로 다음 3-1-5. Object References 뷰 파트에서 다룬다.

3-1-5. Object References 뷰
메모리 프로파일링을 하는 동안 객체가 생성된 위치를 확인 하고자 할 때 [Object References 뷰]를 이용한다. 이 뷰는 객체를 생성시킨 메소드를 보여주며 해당 메소드의 소스코드 위치까지 알려준다.

우리는 이 뷰를 [Memory Snapshot]뷰를 통해 연다는 것을 바로 이전 파트에서 배웠다. 이제 문제의 DataGrid 객체가 어디에서 생성되는지 확인하기 위해 이 뷰를 열어보자.


이 뷰는 객체의 리스트를 보여주는 [Instance] 영역과 해당 객체가 생성된 위치를 보여주는 [Allocation Trace] 영역으로 나뉘어져 있다. 위 그림에서 알 수 있듯이 좌측 [Instance] 영역에서 무수히 많이 생성된 DataGrid 객체를 선택하면 우측 [Allocation Trace]에서 그 객체를 생성한 메소드와 소스 위치까지 파악할 수 있다. 이러한 정보를 이용해 잘못된 애플리케이션을 즉시 수정할 수 있을 것이다.


3-1-6. Loitering Objects 뷰
과거 특정한 시점에 메모리 스냅샷 두개를 저장했고 그 두 시점 사이에서 생성 되었던 객체들을 확인하고 싶을 때 [Loitering Objects 뷰]를 이용한다. 이 뷰는 두 시점 사이에서 생성된 객체와, 그 객체가 사용했던 메모리의 총 합계를 보여준다.

이제 이 뷰를 활용하기 위해 프로파일링을 다시 시작하고, 시작 하자마자 메모리 스냅샷을 저장하고 약 10초뒤 다시 한번 메모리 스냅샷을 저장 해보자. 그리고 [Profile 뷰]에서 두 개의 메모리 스냅샷을 선택하고 Find Loitering Objects 버튼을 누르면 다음 그림처럼 [Loitering Objects 뷰]가 나타날 것이다.


위 그림에서 짧은 시간에 DataGrid 객체가 900개나 생성되고 전체 메모리에서 62%에 해당하는 메모리를 사용하고 있음을 알 수 있다. 이 처럼 이 뷰는 메모리 누수를 발견 하는데 유용하며 [Memory Sanapshot 뷰]와 마찬가지로 특정 객체를 더블클릭 하거나 우측 상단의 빨간색으로 마킹된 아이콘을 누르면 해당 객체가 생성된 위치를 보여주는 [Object References 뷰]를 열 수 있다.


3-1-7. Allocation Trace 뷰
[Allocation Trace 뷰]는 바로 이전 파트에서 배웠던 [Loitering Objects 뷰]와 비슷한데 특정한 두 시점 사이의 메모리 상황을 분석할 때, 호출된 메소드에 대한 정보를 알고 싶을 때 이용한다. 앞서 말했듯이 [Loitering Objects 뷰]가 생성 되었던 객체를 보여줬다면, 이 뷰는 호출된 메소드와 그 메소드가 호출되는 동안 생성한 객체의 수를 비롯하여, 사용했던 메모리 양을 보여준다.

이제 [Profile 뷰]에서 3-1-6 Loitering Object 뷰 파트에서 저장했던 두 개의 메모리 스냅샷을 선택하고, View Allocation Trace 버튼을 누르면 다음 그림처럼 [Allocation Trace 뷰]가 나타날 것이다.


위 그림과 같이 [Allocation Trace 뷰]에는 6개의 컬럼이 존재한다. 이 중 Method, Package 컬럼은 궂이 설명하지 않아도 어떤 컬럼인지 알 수 있을 것이다. 그 두개를 제외한 나머지 컬럼들에 대해 알아보자.
Cumulative Instances
두 시점 사이에서 이 메소드에 의해서 호출된 메소드와 이 메소드 자체에서 생성된 객체의 수이다.

Self Instances
두 시점 사이에서 이 메소드 자체에서 생성된 객체의 수이다.

Cumulative Memory
두 시점 사이에서 이 메소드에 의해서 호출된 메소드와 이 메소드 자체에서 생성된 객체가 사용한 메모리 양이다.

Self Memory
두 시점 사이에서 이 메소드 자체에서 생성된 객체가 사용한 메모리 양이다.

[Allocation Trace 뷰]를 통해서 짧은 시간동안 timerHandler 라는 메소드에서 많은 객체를 생성하고 많은 메모리를 사용한다는 것을 알 수 있다. 위 그림에서 처럼 timerHandler 라는 메소드가 과연 어떠한 객체를 생성했는지는 알 수 없다. 그러나 해당 메소드를 더블클릭 하거나 우측 상단의 빨간색 마킹된 버튼을 누르면 어떤 객체가 생성 됐는지 보여주는 [Object Statistics 뷰]를 열 수 있다. 바로 다음 파트에서 이 뷰에 대해 자세히 알아보겠다.

3-1-8. Object Statistics 뷰
과거 특정한 두 시점 사이에서 호출 되었던 메소드에 대한 메모리 통계정보를 알고 싶을 때 [Object Statistics 뷰]를 이용한다. 이 뷰는 해당 메소드가 수행 되는 동안 생성한 객체가 무엇인지, 그 객체가 얼마나 많은 메모리를 사용했는지 보여준다.

이 뷰는 바로 이전 파트에서 [Allocation Trace 뷰]를 통해 연다는 것을 배웠다. 이제 특정 메소드의 통계 정보를 보기 위해 이 뷰를 열어보자.


위 그림처럼 이 뷰는 크게 3가지 영역으로 구분할 수 있다.
번 영역은 호출된 메소드에 대한 요약된 정보로서 [Allocation Trace 뷰]에서 보여지던 정보와 동일하다.
번 영역은 이 메소드 자체에서 생성된 객체와 그 객체가 사용하는 메모리 양을 보여준다.
번 영역은 이 메소드에 의해 호출된 다른 메소드에서 생성던 객체와 그 객체가 사용하는 메모리 양을 보여준다.
이 처럼 [Object Statistics 뷰]는 이제껏 봐왔던 뷰들에 대한 전체적인 정보를 보여주는 통계뷰 라고 할 수 있다. 이러한 통계정보를 바탕으로 보다 종합적인 메모리 분석을 할 수 있을 것이다.

우리는 지금 까지 플렉스빌더에서 메모리 프로파일링을 통해 메모리 누수 감지와 원인 발견 및 애플리케이션 전체적인 메모리 상황에 대한 정보를 알 수 있었다. 이런 정보를 안다면 애플리케이션 설계에 있어서도 도움이 될 것이다. 이제 메모리 상황이 아닌 성능에 초점을 둔 퍼포먼스 프로파일링에 대해 알아 보도록 하자.


3-2. 퍼포먼스 프로파일링
퍼포먼스 프로파일링은 애플리케이션에서 응답이 느린 메소드를 찾아내거나, 성능이 향상될 수 있는 메소드를 찾아 내고자 할 때 이용한다. 퍼포먼스 프로파일링은 이 두가지 타입의 메소드를 최적화 하기 위한 리팩토링 정보를 제공하여 애플리케이션의 전체적인 성능을 향상 시킬 수 있다.

우리는 잘못된 예제코드를 이용하여 수행시간 가장 긴 메소드와 빈번히 호출되는 메소드를 찾아낼 것이다. 예제코드는 다음과 같다.


위 예제코드를 다 적었다면 프로파일링을 시작해보자. 이번에는 퍼포먼스 프로파일링만 하기 때문에 실행 옵션을 묻는 창에서 가장 아래 있는 Enable performance profiling 항목에만 체크를 한다. 그리고 나서 애플리케이션이 시작되면 화면에 보이는 버튼을 10회 누른다. 플렉스빌더는 프로파일링이 시작된 이후로 성능 데이터를 수집 하는데, 성능 데이터는 메소드 호출시간과 횟수이다. 따라서 여러분이 버튼을 10회 눌렀다면 버튼에 의해 실행된 메소드 정보가 수집 되었을 것이다. 이제 플렉스빌더로 돌아가서 [Profile 뷰]에 있는
Capture Performance Profile 아이콘을 누르면, 다음 그림처럼 플렉스빌더가 아이콘을 누른 시점까지 수집했던 성능 데이터를 저장하게 된다.


퍼포먼스 데이터가 저장되면 위 그림처럼 [Profile 뷰]에 목록으로 추가된다. 또한 하나 이상의 퍼포먼스 데이터를 저장할 수 있으며, 플렉스빌더가 수집한 퍼포먼스 데이터를 초기화 하고 싶다면
Reset Performance Data 아이콘을 누르면 된다. 저장된 목록중 하나를 더블클릭하면 퍼포먼스 데이터를 볼 수 있는 [Performance Profile 뷰]가 열린다. 다음 파트에서 [Performance Profile 뷰]를 통해 수집된 퍼포먼스 데이터를 확인해 보도록 하겠다.

3-2-1. Performance Profile 뷰
[Performance Profile 뷰]는 퍼포먼스 프로파일링을 하는 동안 사용하는 가장 중요한 뷰 이다. 이 뷰는 메소드 호출에 관련된 통계를 보여주며, 이러한 정보는 애플리케이션의 병목현상을 개선하거나 수행속도를 높이는 정보로 이용될 수 있다.

[Profile 뷰]에서 저장된 퍼포먼스 데이터 항목을 더블클릭 하면 다음 그림처럼 [Performance Profile 뷰]가 열릴 것이다.

위 그림과 같이 [Performance Profile 뷰]에는 6개의 컬럼이 존재한다. 이 중 Method, Package 컬럼은 궂이 설명하지 않아도 어떤 컬럼인지 알 수 있을 것이다. 그 두개를 제외한 나머지 컬럼들에 대해 알아보자.
Calls
퍼포먼스 데이터가 저장된 시점까지 메소드가 호출된 횟수이다.

Cumulative Time

이 메소드에 의해서 호출된 메소드들의 총 수행 시간이다.

Self Time
이 메소드 자체의 수행 시간이다.

AVG. Cumulative Time
이 메소드에 의해서 호출된 메소드들의 평균 수행 시간이다.

AVG. Self Time
이 메소드 자체의 평균 수행 시간이다.

위 그림은 Cumulative Time 컬럼을 눌러서 내림차순 정렬한 것 이다. 정렬을 통해서 가장 응답이 느린 메소드를 확인해 본 결과, 자체적인 수행시간이 가장 느린 메소드는 slow() 임을 확인할 수 있다. 이제 여러분이 직접 Calls 컬럼으로 정렬을 하면 가장 많이 호출된 메소드는 fast() 임을 확인할 수 있을 것이다. 이제 여러분은 메소드의 수행 시간을 알게 되었으므로 리팩토링을 통해 성능 향상을 꽤할 수 있을 것이다.

또한 이 뷰에서 특정 메소드 항목을 더블클릭 하거나 위 그림의 우측상단 빨간색 마크된 아이콘을 누르면 해당 메소드의 좀 더 진보된 정보를 볼 수 있는 [Method Statistics 뷰]를 열 수 있다. 다음 파트에서 [Method Statistics 뷰]에 대해 자세히 알아 보겠다.

3-2-2. Method Statistics 뷰
퍼포먼스 프로파일링 하는동안 호출된 메소드에 대한 성능 통계정보를 알고 싶을 때 [Method Statistics 뷰]를 이용한다. 이 뷰는 호출된 메소드에 대한 수행시간과 더불어 메소드 내에서 호출된 다른 메소드나, 자신이 어디서 호출되었는지 정보를 제공한다.

이제
[Performance Profile 뷰]에서 Cumulative Time 이 가장 오래 걸린 execute() 항목을 더블클릭해서 이 뷰를 열어보자.


이 뷰는 크게 3가지 영역으로 구분할 수 있다.
번 영역은 이 메소드 자체 수행시간으로써 [Performance Profile 뷰]에서 보여지던 정보와 동일하다.
번 영역은 이 메소드를 호출한 메소드에 대한 수행 시간을 보여준다.
번 영역은 이 메소드에 의해 호출된 다른 메소드들의 수행 시간을 보여준다.
이 처럼 [Method Statistics 뷰]는 수행시간과 더불어 메소드들의 흐름과 같은 최적화 하기 유용한 정보를 제공한다. 애플리케이션의 성능과 흐름을 파악하는 것 만으로도 앞으로 여러분이 무엇을 해야할지 알게 될 것이다.


4. 맺음말
지금까지 프로파일링에 대해서 알아봤다. 이 글에서 소개한 방법으로 메모리와 퍼포먼스를 측정하여 여러분의 애플리케이션의 성능을 향상시켜 보도록 하자. 끝으로 프로파일링 또한 디버깅과 마찬가지로 개발이 끝난 후가 아니라 개발 과정의 일부분으로 행해 진다면 좋은 품질의 애플리케이션을 만들 수 있을 것이다.

'Flex/Air' 카테고리의 다른 글

Adobe Flash Catalyst Beta review  (0) 2009.07.05
Flex4 SDK beta review  (2) 2009.07.03
Flex Builder에서 디버깅&프로파일링 하기 -2부-  (9) 2009.05.25
Flex Builder에서 디버깅&프로파일링 하기 -1부-  (0) 2009.04.20
AirMusic  (10) 2009.03.31
WebUtil Framework  (2) 2008.05.08
Posted by 째코

댓글을 달아 주세요

  1. 모험가 2009.05.25 09:20  댓글주소  수정/삭제  댓글쓰기

    개발하는대에 있어서 큰 도움이 되는 글 같습니다~ 감사합니다 ㅎㅎ

  2. 검쉰 2009.05.25 16:59 신고  댓글주소  수정/삭제  댓글쓰기

    글 내용 좋습니다 ;)

  3. 지돌스타 2009.07.08 16:13  댓글주소  수정/삭제  댓글쓰기

    글이 정말 상세하네요. 너무 잘봤습니다.

  4. LazyArtist 2010.03.25 15:28  댓글주소  수정/삭제  댓글쓰기

    많은 참고가 됐습니다~
    이거 정리하느라 고생하셨겠네요~
    정말 감사해요~ ^^;

  5. FCliver 2011.03.19 10:52  댓글주소  수정/삭제  댓글쓰기

    와, 대단하십니다. 영양가 넘치는 포스팅 잘 보고 갑니다 ^^

  6. 윤여석 2012.05.22 21:31  댓글주소  수정/삭제  댓글쓰기

    아,, 정말 미치는줄 알았는데 이거보고 조금씩 풀려가네요 ㅎ 오래전에 쓰신글인데 정말 잘 보고 갑니다. ㅎㅎ