Hw-config-defs.h
에서 vm_heapSize 에 숫자를 수정.


=======================================================================================

device/htc/passion/passion.mk


...

 42 
 43 # This is a high density device with more memory, so larger vm heaps for it.
 44 PRODUCT_PROPERTY_OVERRIDES += \
 45     dalvik.vm.heapsize=24m
 46


'안드로이드' 카테고리의 다른 글

윈도우 환경에서 CTS 돌리기  (0) 2011.03.11
CTS 정리  (0) 2011.03.10
참고 사이트  (0) 2011.03.09
Activity Rotation 시 처리 프로세스  (0) 2011.03.08
GC 호출시 호출되는 함수[finalize]  (0) 2011.03.08

'안드로이드' 카테고리의 다른 글

CTS 정리  (0) 2011.03.10
전체 컴파일 시 Dalvic Heap Memory Size 늘리기  (0) 2011.03.09
Activity Rotation 시 처리 프로세스  (0) 2011.03.08
GC 호출시 호출되는 함수[finalize]  (0) 2011.03.08
JNI 사용하기  (0) 2011.03.08
센서로 전환시
 PhoneWindowManager.java [onOrientationChanged]
  --> WindowManagerService.java [mWindowManager.setRotation(rotation,
                                                                          falsemFancyRotationAnimation,)]
  --> WindowManagerService.java [setRotationUnchecked(rotation,
                                                                 alwaysSendConfiguration, animFlags);]
  --> WindowManagerService.java [setRotationUncheckedLocked(rotation,
                                                                                                       animFlags);]


키패드로 화면 전환시
  --> InputManaer.java [notifyLidSwitchChanged(long whenNanos, boolean lidOpen)]

  --> WindowManagerService.java [notifyLidSwitchChanged(long whenNanos,
                                                                                               boolean lidOpen)]
  --> PhoneWindowManager.java [notifyLidSwitchChanged(long whenNanos,
                                                                                              boolean lidOpen)]
  --> PhoneWindowManager.java [updateRotation(int animFlags)]

  --> WindowManagerService.java [mWindowManager.setRotation(rotation,
                                                                          falsemFancyRotationAnimation,)]
  --> WindowManagerService.java [setRotationUnchecked(rotation,
                                                                 alwaysSendConfiguration, animFlags);]
  --> WindowManagerService.java [setRotationUncheckedLocked(rotation,
                                                                                                       animFlags);]


'안드로이드' 카테고리의 다른 글

전체 컴파일 시 Dalvic Heap Memory Size 늘리기  (0) 2011.03.09
참고 사이트  (0) 2011.03.09
GC 호출시 호출되는 함수[finalize]  (0) 2011.03.08
JNI 사용하기  (0) 2011.03.08
Memory Analyzer 로 heap dump 해석하기  (0) 2011.02.25

/** 
Garbage Collector를 이용한 finalize()호출 I 
**/ 
import java.io.*; 
class FinalMan{ 
    private FileWriter fw = null; 
    public FinalMan(String filename) throws IOException{ 
        this.fw = new FileWriter(filename); 
    } 
    public void writeData(String str) throws IOException{ 
        this.fw.write(str); 
    } 
    protected void finalize() throws Throwable, IOException{ 
        if (this.fw != null){ 
            this.fw.close(); 
        } 
        System.out.println("finalize()의 파일 닫기");         
        super.finalize(); 
    }  
} //end of FinalMan 

public class FinalManMain{ 
    public static void main(String[] args) throws Exception{ 
        System.out.println("프로그램 시작"); 
        //단순블럭 
        { 
            FinalMan fm = new FinalMan("finalize.dat"); 
            fm.writeData("안녕하세요"); 
            fm.writeData("Hello"); 
            fm = null; 
        } 
        System.gc();//가비지 콜렉터 구동 
        System.out.println("프로그램 종료"); 
    } //end of main 
} //end of FinalManMain class 
//㉶------------------------------------------------------------------㉳ 
/*** 
C:javasrcchap10>javac FinalManMain.java 
C:javasrcchap10>java FinalManMain 
프로그램 시작 
finalize()의 파일 닫기 
프로그램 종료 
***/

 

위의 예에서 FinalMan의 생성자에서 매개변수로 주어진 파일명으로 FileWriter를 생성하고 있습니다.  

◈ private FileWriter fw = null; 
◈ public FinalMan(String filename) throws IOException{ 
◈         this.fw = new FileWriter(filename); //문자 파일 스트림 생성 
◈ } 

그리고 FileWriter fw를 이용해서 주어진 문자열을 파일에 기록하는 메서드를 포함하고 있습니다. 

◈ public void writeData(String str) throws IOException{ 
◈        this.fw.write(str); //스트림을 이용해서 파일에 문자열 기록 
◈ } 

그런데 이상한 것이 있습니다. 데이터를 기록하기 위해서는 writeData()를 호출하면 되지만 FinalMan 어디에도 생성된 스트림을 닫아주는 곳은 없습니다. 즉 위의 FinalMan 클래스에서 보여주고자 하는 것은 FinalMan의 객체가 더 이상 쓸모가 없을 때 호출되는 finalize()에 스트림을 닫아주고자 하는 것입니다. 어차피 가비지 콜렉터에 의해서 finalize()가 호출될 것이고 객체가 소멸되기 전까지는 스트림을 닫지 않겠다는 것입니다. 

▣ finalize()의 재정의  
◈ protected void finalize() throws Throwable, IOException{ 
◈         if (this.fw != null){ 
◈             this.fw.close(); 
◈        } 
◈         super.finalize(); 
◈    }  

가비지 콜렉터에 의해서 객체가 소멸되면서 FinalMan의 finalize()가 호출될 것이며, 자동으로 스트림을 닫는 작업과 상위 클래스의 finalize()를 호출하는 작업이 이루어지는 것입니다. 

finalize()가 호출되는 것을 보장하기 위해서 독특한 방법을 이용하고 있습니다. 단순히 블록 처리를 하고 블록 내에서 객체를 만들고 있습니다. 그리고 블록 내에서 생성된 객체를 null로 초기화하고 있습니다. 이렇게 되면 생성된 객체가 블록 내부의 지역 변수가 되기 때문에 블록이 끝나면 가비지 콜렉터의 수집 대상이 되는 것입니다. 엄밀하게 말하면, 지역적으로 생성된 객체의 참조값이 다른 곳에서 사용되지 않는다는 것이 보장되면 가비지 콜렉터의 수집대상이 되는 것입니다. 

◈ { 
◈        FinalMan fm = new FinalMan("finalize.dat"); 
◈        fm.writeData("안녕하세요"); 
◈        fm.writeData("Hello"); 
◈        fm = null; 
◈ } 

가비지 콜렉터의 수집 대상이 되도록 만드는 것은 아주 중요합니다. 특정 블록 내에서 생성된 객체의 참조값을 다른 곳에서 사용하지 않는다는 것을 보장하기 위해서 블록 내에서 생성된 객체의 참조값을 null로 초기화하고 있습니다. 이 구문이 바로 참조값을 사용하지 않겠다고 보장하는 구문이 되는 것입니다.  

▣ null의 초기화 여부 
◈ 보통의 경우 사용하지 않는 참조값일 경우 가비지 콜렉터가 알아서 하기 때문에 별로 신경 쓰지 않는다. 하지만 사용자가 사용하지 않는 객체를 null로 명시화하면 프로그램은 더욱 유연하게 동작한다. 

가비지 콜렉터는 메모리가 부족하거나 메모리의 청소가 필요할 때 자동으로 구동되는 가상머신의 시스템 스레드입니다. 보통 이 스레드를 Finalizer라고 칭합니다. 필요에 의해서 Finalizer 스레드가 동작하지만 사용자가 직접 Finalizer를 구동하고자 한다면 다음과 같은 구문을 사용하면 됩니다. 

◈ System.gc(); 

지역적으로 선언된 객체가 더 이상 참조값을 사용하지 않는다는 것이 보장되었으며, Finalizer까지 구동되었다면, 지역적으로 선언된 객체 FinalMan fm의 finalize()가 호출되는 것을 확인할 수 있을 것입니다.


출처 : http://www.softpackage.com/bbs/bbs/content.asp?grp=devforum&board=java&num=104&opt=

안드로이드 개발을 하면서 가장 흥미롭거나 유용하다고 생각하는것 중에 하나가 JNI 이다.

C 개발된 소스를 그데로 라이브러리화 해서 java(android) 에서 사용 있다는 것은 개발자로서 축복 받은 일이다~~

작년에 프로젝트 도중에 어찌어찌 하다보니 내손에 c 구현된 천지인 소스가 들어왔다~ 생각보다 소스량이 많아 놀랐지만, 왠만한것은 할수 있다.

역시나 저작권덕에 배포는 없고 혼자 조용히 가지고만 있다ㅠㅠ

시간이 남으면 해당 라이브러리에 카메라 소스붙여서 요새 인기좋다는 투명키패드(?) 어플리케이션을 만들어 볼까 생각중이다ㅋ

잠깐 시간이 남아 천지인 소스를 안드로이드 라이브러리로 포팅해 빌드를 해보았다. jni 포팅에 대한 내용을 아래에 정리해 본다~

 

우선 ndk 설치 c 파일을 빌드하기 위해 <JNI_HOME>/<PROJECT_NAME>/project/jni 경로에 있는 Android.mk 파일을 작성해야 한다
자세한 작성법은 <JNI_HOME>/docs/ANDROID-MK.TXT (NDK 설치한 폴더)  설명되어 있다
작성법에 따라 아래와 같이 Android.mk 파일을 작성해 보았다

 

c 에서 일반적인 makefile 문법과 동일하다.

local_module 빌드명을 적는다. 이름은 빌드시에 필요한 이름이니, 적당하게 작명해서 적어준다.

bulid_shared_library 공유 라이브러리로 빌드한다는 뜻이다.

local_src_files 빌드에 필요한 c 파일들을 주루룩 나열해 주면 된다. 나열 순서는 상관 없다~

자세한 내용은 역시나 docs 폴더에 ANDROID-MK.txt 자세히 설명되어 있다. (영어로..)

ndk 아닌 다른 빌더에서 빌드된 .so 파일은 아쉽게도 정식적인 방법으로는 물릴수 없다. 요새 검색도중 크로스 컴파일해서 물릴수 있다고 하던데..

그렇게 까지 하면서 물릴만한 라이브러리를 보유하고 있지 않아 패스~

(그러고 보니.. 프로젝트도중 암암리에 얻게된 문자인식 라이브러리가 있긴하다-_-;; 이건 나중에 시간되면 해보기로 하고~)

다음 단계로 넘어가 c 구현된 소스들을 java에서 호출가능하게 하기 위해 약간의 포팅 작업을 거쳐야 한다.

C 구현

NaraAutoHandler.c, NaraAutomata.c, NaraCode_TKS.c 파일들은 automata 코드이고, NaraJni.c 파일은 c 코드와 java 코드를 연결하기 위한 포팅 레이어를 구현하였다.

나름 대범하게 원래 소스를 토씨하나 바꾸지 않고 그데로 사용하였다;; (배포하지 않을 것이기 때문에..)
포팅된 코드는 아래와 같다. 

 

#include <string.h>

#include <jni.h>

 

#include "NaraAutoDef.h"

#include "NaraAutoHandler.h"

#include "NaraAutomata.h"

#include "NaraCode_TKS.h"

 

#define S_OK               0

#define E_ERROR            -1

 

sNaraIMEState*     ime            = NULL;

char*                      buf     = NULL;

jbyteArray         jbtbuf  = NULL;

 

jint Java_com_example_keypad_KorKeypad_NaCInit( JNIEnv* env, jobject thiz , int maxsize)

{

   

    ime = (sNaraIMEState*)malloc(sizeof(sNaraIMEState));

    if(!ime)

            return E_ERROR;

   

    buf = (char *)malloc((sizeof(char) * maxsize) + 1);

    if(!buf)

            return E_ERROR;

 

    NaC_Init(ime, buf, maxsize);

   

    return S_OK;

   

}

 

void Java_com_example_keypad_KorKeypad_NaCSetCurrentMode( JNIEnv* env,

                                                  jobject thiz , int mode)

{

    NaC_SetCurrentMode(ime, mode);

}

 

void Java_com_example_keypad_KorKeypad_NaCKeyIn( JNIEnv* env,

                                                  jobject thiz , char input)

{

    NaC_KeyIn(ime, input);

}

 

 

jbyteArray Java_com_example_keypad_KorKeypad_NaCGetBuffer( JNIEnv* env,

                                                  jobject thiz)

{

 

    if (jbtbuf != NULL)

    {

            (*env)->DeleteGlobalRef(env, jbtbuf);        

    }

 

    char* src = NaC_GetBuffer(ime);

    int len = strlen(src);

    jbtbuf = (*env)->NewByteArray(env, len + 1);

    (*env)->SetByteArrayRegion(env, jbtbuf, 0, len, src);

 

    return jbtbuf;

 

}


간지나게 포팅 풀소스를 공개 했다.

(라고 해바야 별거 없다. ㅠㅠ)

원래 함수들은 많은데.. 우선 필요한 함수들 몇개만 포팅했다.

프로젝트 진행할때, virtual keypad full screen keypad input 관련된 interface 들이랑 모두 본인 일이었던 지라.. 포팅하며 오랜만에 향수(??) 느낄수 있었다 ㅠㅠ

보아도 전형적인 c 스타일의 function pointer table 이용한 방식이다~ cpp 작성하면 function 포인터가 아닌 클래스 형식으로 env->func(); 요런식으로 바뀐다. 그런데 본인은 cpp 빌드하면 자꾸 다른 빌더로 자동으로 바뀌는 바람에 c 작성해 컴파일 했다~

코드 작성 주의점은 함수명은 다음과 같은 방식을 따라야 한다

JAVA_<패지키 명>_<클래스 명>_<함수명> (JNIEnv* env, jobject thiz, <매개변수>)

 

<함수명> 에는 '_' 문자가 들어가서는 안된다처음에 못도 모르고 함수명에 언더바를 넣었다가.. java 에서 호출하는데, 자꾸 vm 죽길래 바보처럼 한참을 헤메기도 했다;;

JAVA_  java 에서 c jni 호출한다는 뜻이다. 반대로 c 에서 java 소스를 수도 있다.

패키지명과 클래스명이 일치해야 java 에서 call 가능하다.. 따라서 java 단에서도 jni 콜을 위한 전용 클래스를 하나 두어야 된다는 뜻이 된다.

VM 통해서 콜하기 때문에 속도도 왠만큼 보장된다고 어디서 본것 같다. 그래서 이미지 처리등에 관한 어마어마한 코어단 소스를 jni 만들어 호출한다고 하기도 한단다.
자바에는 포인터가 없기때문에 배열 포인터 같은 경우 jni.h 정의되있는 jbyteArray, jcharArray, jintArray 등등을 사용해야 한다
자바로 보내지는 객체는 C 단에서 메모리를 할당하기 때문에 메모리 관리에 신경 써줘야 한다.

포팅해주는 쪽에서 메모리를 관리하는게 본인에게는 편하기 때문에 이렇게 구현했다. 콜러쪽에서 메모리 관리를 해주어도 당연히 된다^^

포팅 레이어를 구현했다면, 다음은 바로 빌드를 하면 된다~

 

빌드

apps/<Project >/Application.mk APP_MODULES  apps/<Project >/project/jni/Android.mk LOCAL_MODULE 모듈명을 정확히 작성  빌드 작업은 간단하게 ndk 폴더에서 (apps, build, docs, out 폴더가 있는 ) 아래와 같이 실행하면 된다. 

 

make APP=<module >


빌드가 위와같이 성공했다면 project/libs/armeabi 폴더에 lib<모듈 >.so 파일이 생긴다. 

빌드가 완료 되었다면 이제 java 에서 호출하는 일만 남았다 ++!!

Java 구현

위와 같이 라이브러리 파일을 생성하였다면 생성된 파일을 이클립스 프로젝트에 동일하게 libs/armeabi/ 폴더에 복사  해당 라이브러리 파일에 있는 함수들을 아래와 같이 정의 한다. 

미리 구현된 소스가 아니라 처음부터 c 구현한다면 java 프로젝트 자체를 해당 폴더에 import 시키는것을 추천한다. jni 빌드하고 .so 파일 복사하고 java 컴파일하는 단계를 한번에 처리할 있다~~

 

함수 정의 시에는 c 파일와 달리 함수명만 작성하면 된다

함수를 클래스 내에 정의 했다면 라이브러리 파일이 호출 가능하다
jni 호출 구조는 간단하게 아래와 같다고 한다

 

어디서 퍼온 사진인데.. 시간이 지나서 출처가 기억나지 않는다. 안드로이드 dev 사이트 인가?? ㅡㅡㅋ;;

어쨋든 직관적으로 한눈에 호출구조를 있다. 사실 내부는 엄청 복잡하겠지만.. 단순하게 java call -> lib -> return 이라는 형식으로 단순화 하였다

 

우선 위에서 열심히 만든 .so 파일 로드 해주시고~ 바로 바로 호출해서 쓰면 된다~

 

    static {        
        System.loadLibrary("keypad-kor");        
    }

 

자바 코드 구현 주의점은 byteArray 리턴받았을 경우 한글 지원을 위해 아래와 같이 euc-kr 지원 해야한다

아직나에겐 복잡하기만한 망할 유니코드..!!

그냥 단순 간단하게 String 객체를 euc-kr 하나 생성해 주었다~ 어차피 테스트용 이니~~ 메모리따위 가볍게 무시~~

 

 

포팅된 jni 오토마타 이용하여 다음의 "ㅇㅏㄴㄷㅡㄹㅗㅇㅣㄷㅡ" 한글을 조합한 결과는 아래와 같다.

 



출처 : http://blog.naver.com/oh4zzang/40111762322


- その1: 서버 백업
- その2: 프리즈의 원인과 가비지 콜렉션
- その3: 사무라이로 heap 사용량 확인
- その4: 릭 개소를 확인하는 여러가지 방법
- その5: Memory Analyzer 로 heap dump 해석

Eclipse Memory Analyzer(MAT)를 사용하여 인스턴스가 얼마나 메모리를 잡아먹고 있는지를 알 수 있습니다.

용어해석
 *   Shallow Heap:  1개의 오브젝트가 소비하는 메모리. 1개의 참조에 대해 32 bit가 소비된다.
                               예를 들면, Integer에서는 4바이트, Long에서는 8바이트
 *  Retained Heap:  GC에 의해 제거되는 일련의 오브젝트가 사용하는 Shallow Heap의 합계.
                               오브젝트의 트리가 직접 사용하고 있는 메모리

heap dump는 JDK 에 들어있는 jmap 커맨드로 뽑아냅니다.

jmap -heap:format=x [pid]  또는  jmap -heap:format=b [pid]  의 형태로 실행하면 heap dump를 xml 형식, 또는 바이너리 형태로 추출합니다.
보통은 쌩으로 heap dump를 사람이 읽는것은 힘들기 때문에 xml 형식은 사용하지 않으며, 바이너리로 출력합니다.
바이너리 형식의 heap dump는 Eclipse Memory Analyzer 라는 툴로 해석할 수 있습니다.
Eclipse Memory Analyzer 는 SAP 가 개발한 Eclipse RPC 를 베이스로 멀티플레이트 폼 어플리케이션입니다.
꽤 괜찮은 녀석이죠.


Memory Analyzer 를 기동한 샷~!

Memory Analyzer 를 기동하면 heap dump를 간단히 읽을 수 있습니다.
[File > Open Heap Dump...] 로 폴더를 열어, heap dump를 선택합니다.


heap dump 를 열면 요롷게 보이죠

메모리 Leak 문제의 조사는 크게 2가지가 있습니다.

 1. heap 에서 차지하는 비율이 큰 오브젝트를 찾는것, 이것은 heap dump를 한개를 열어보면 해석이 가능합니다.
 2. 어플리케이션을 작동시키는 과정을 간단하게 단조증가시키면서 오브젝트를 발견하는 방법.
    구체적으로 heap dump 를 2회이상 취득해서 차분을 구하여 해석을 합니다.

"1." 에서 덩치가 큰  오브젝트 또는 대량으로 존재하는 오브젝트를 보는것으로 원인을 분석해 봅시다.
하지만 그런 오브젝트는 보통 캐쉬로 되어있는것이 많습니다. 계속 증가되는 형태가 아닌 경우는 조사해도 별볼일 없습니다.
정말 릭 되어 있는 오브젝트를 확인하기 위해서는 "2." 에서 단조증가되고 있는 오브젝트 해석법으로 해야 합니다.


1. heap 영역을 선점하는 비율이 높은 오브젝트 확인법

heap dump를  Memory Analyzer 로 열어 표시되는 over view화면에서 "Leak Suspects" 링크를 클릭!

커다란 오브젝트를 대략적으로 판단해서 픽업해 줍니다.
「대략」적으로 나오는 그림이니 반드시 Leak되어진 오브젝트가 검출된다고는 할 수 없죠

Leak Suspects 를 열었을때

위에는 org.apache.jasper.runtime.BodyContentImpl 클레스의 인스턴스가 108 개로、합계419MB(heap中72.26%)를 차지하고 있네요.
org.apache 라는 패키지로부터 Apache 프로젝트의 컴퍼넌트에 존재하는 것을 알 수 있습니다. 그리고 jasper 라는 이름은 Apache 의 jsp 코드죠.
인스탄스의 수는 108 개로 아주 많은건 아니지만 하나하나 사이즈는 심상치 않네요.
하나의 인스턴스는 뭘 기록하고 있을까요
? 함 봅시다.
이번엔 dominator tree 뷰에서 오브젝트의 속을 까봅시다.
dominator tree를 여는것은 아래 그림처럼 툴바에서 선택합니다.

dominator tree를 여는 아이콘

dominator tree 를 열면 큰 오브젝트 순서대로 소트된 인스턴스 일람이 보입니다.
그리고 이것저것 인스턴스 트리를 전개하면, 보유하고 있는 필드와 속 알맹이를 확인할 수 있습니다.

dominator tree 표시

이번엔 dominator tree 에서、BodyContentImpl 에는 꽤나 사이즈가 큰 char 배열이 있는것을 알게 되었습니다.
Inspector 페인으로 간단한 배열의 속을 미리볼 수 있지만, 부분부분 밖에 볼 수 없네요.
하지만 파일로 저장하면 상세 하게 볼 수 있습니다.


오브젝트 알맹이를 파일로 저장


보존한 char 배열의 알맹이를 확인

알맹이를 view 커맨드로 확인하면 html 이 기록되는 것을 확인 할 수 있습니다.
좀 더 자세히 보면 ・・・・썩스 그다지 크지 않는 영단어가 <div class="trackbackheader">..</div> 라는 태그에 싸여져
대량으로 들어가 있습니다.

이건 트랙빽 스펌메일 이군요.
<img border="0" src="/jira/images/icons/document_exchange.gif" width=16 height=16 align=absmiddle> 의 요소가 보이는데
 
Jira 가 들어가 있네요.
Jira 는 자신의 오픈 소스 프로젝트의 버그 트랙킹에 사용하고 있는 Web 어플리케이션입니다.
Jira 를 사용하면 뭔가 JBoss Web(JBoss 내장의 Tomcat 베이스의 컨테이너)로 Leak 하는 것일지도...

다음은 BodyContentImpl 이외에도 증가하고 있는 오브젝트가 없는지, heap 덤프의 차분도 확인해 보기로 하겠습니다.



2. 단조증가되고 있는 오브젝트 확인
heap dump의 차분을 내는것은 heap dump를 두개 열어서 히스토그램 뷰(막대 그래프의 아이콘)가 열린 상태에서 좌우의 화살표를 누릅니다.

heap dump 비교

그러면 Select baseline 이라는 다이얼로그가 뜨는데 차분을 뽑고싶은 또다른 heap dump를 선택합니다.

Select baseline에서 차분을 보고싶은 대상의 heap dump를 선택

차분이 나오면, "Objects" 즉 인스턴스 수로 소트해 봅시다.
그럼 재미있는 오브젝트가 텨 나옵니다.
com.atlassian.trackback.Trackback 라는 오브젝트가 20,211개가 증가해 있는 것을 알 수 있겠습니다.

차분을 취득해서 나온 - com.atlassian.trackback.Trackback

atlassian 은 Jira 를 개발한 회사입니다. 트랙백 스팸메일을 대략으로 접수하서 트랙백을 표현하는 오브젝트가 증가하는것 같네요.

"com.atlassian.trackback.Trackback" 로 검색한 결과 leak에 관련된 정보는 없네요.

이번엔
"jira tomcat leak"로 검색! 빙고!
05.03.04 Tomcat 6.0 - JIRA 오브젝트 메뉴얼 (3.12.2版 - 최신) - Atlassian Confluence
Tomcat 의 메노리 설정을 수정

Tomcat는, 큰 JSP의 페이지를 리퀘스트 하면 메모리 leak 되어 버립니다.
이것을 피하기 위해서, bin/setenv.sh를 다음과 같이 설정해 주세요.

export CATALINA_OPTS="$CATALINA_OPTS -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true"

제대로 문서에 써 있는 설정을하지 않았던 것이 원인이었습니다.
LIMIT_BUFFER 옵션에 대해서는 이하의 페이지로 도입의 경위가 자세하게 설명되고 있습니다.


Bug 37793 – org.apache.jasper.runtime.BodyContentImpl doesn't reset the 'cb' character array, causes memory leak

Jira 의 issue 는 여기문서 참조
[#JRA-10145] Set tomcat flag to not re-use buffers, as they result in OutOfMemoryErrors - Atlassian JIRA

아무래도, Tomcat 은 버퍼를 재이용하는 구조가 있는 것 같아서,
매우 큰 컨텐츠를 출력하면 버퍼로 heap가 넘쳐 버리는 것 같습니다.
이 기입 버퍼를 무진장하게 늘리지 않기 위한 옵션이 LIMIT_BUFFER군요.

즉, 이번 메모리 leak 문제의 발생 스텝은 이렇게 상상할 수 있습니다.
 1.  트럭 백 스팸메일을 대량으로 받아 특정의 페이지의 사이즈가 증가됨
 2.  검색 엔진의 클로러에 증가된 페이지를 열람한다
 3.  버퍼가 증가됨

서버는 Tomcat는 아니고 JBoss로 운용하고 있습니다만,
Web 컨테이너인 JBoss Web는 Tomcat  의 기반이므로 이 옵션이 제대로 효과가 있었습니다.

트랙백 오브젝트가 대량으로 있는 것은 좋은 상태인지는 모르겠습니다만,
원래 트랙백 기능은 현재의 곳에는 필요없기 때문에, 관리 화면으로부터 무효로 설정해 버렸습니다.


트랙백 기능을 OFF 로 설정

LIMIT_BUFFER 옵션의 설정과 트랙백의 OFF 설정을 실시하고 나서 1주간 이상 지납니다만,
현재의 heap 사용량은 일정하고 안정적으로 가동하고 있습니다.

메모리 릭의 트러블 슈팅은 차분히 원시 코드를 바라보거나
프로파일러를 사용해 현상을 재현시키는 조사 방법이 유명하네요.
그러나 heap 덤프나 Memory Analyzer를 사용하는 방법도 쉽게 접근 할 수 있을 것입니다.
메모리 릭 트러블은 장기간 가동하고 처음으로 나타나는 것도 귀찮은 문제입니다.
트러블이 발생하고 나서 당황하는 일이 없게, 미리 heap 덤프를 사용한 해석하는 연습을 해 두면 좋을것 같습니다.

번역하고나니 어설픈 부분도 있네요
출처: http://samuraism.jp/diary/2008/11/10/1226316240000.html

자바 힙 덤프 분석기는 jhat등 여러가지 툴이 있지만,
최근에 발견한 Eclipse Memory Analyzer 라는 프로그램이 있다.

http://www.eclipse.org/mat/

다운로드하여 압축을 해제하고, 이클립스만 수행하면 된다.
단, 기본 자바 VM을 사용할 때 발생한 HPROF 덤프 파일의 확장자는 반드시 hprof 여야만 읽을 수 있다.

작성된 힙 덤프 파일을 이 프로그램에서 읽으면 다음과 같은 화면을 제공한다.
사용자 삽입 이미지

'안드로이드' 카테고리의 다른 글

JNI 사용하기  (0) 2011.03.08
Memory Analyzer 로 heap dump 해석하기  (0) 2011.02.25
OutOfMemoryError  (0) 2011.02.22
Android Bitmap Object Resizing Tip  (0) 2011.02.22
우분투 환경에서 디바이스 드라이버 설정하기  (0) 2011.02.22

# cd /tmp
# wget http://www.sputnick-area.net/scripts/vmware7.1.1-patch-kernel-2.6.35.bash
# sudo chmod +x vmware7.1.1-patch-kernel-2.6.35.bash
# sudo ./vmware7.1.1-patch-kernel-2.6.35.bash
# vmware-modconfig --console --install-all
Wine 설치
     [프로그램]-[추가/제거...]에서 Wine을 설치합니다. Wine은 MS윈도우 실행 프로그램을 리눅스에서 실행할 수 있도록 하는 소프트웨어입니다.

      wine(1).png

  
     [시스템]-[관리]-[시냅틱 꾸러미 관리자]를 실행합니다. cabextract 패키지를 설치합니다. ie4linux를 설치 하기 위해서 필요한 패키지입니다.

      cabextract.png

 출처 : http://sardonyx.springnote.com/pages/3283501

가상 OS를 동작하기 위해서 Linux에서 사용할수 있는 것은 몇가지가 있다.
대표적인 것으로 Virtual Box, VMWARE Workstation, VMWARE Server등이 있다.
Virtual BOX, VMWARE Server는 프리웨어로 사용하는데 제약이 없지만
VMWARE workstation은 상용으로 사용기간 제약을 가지고 다양한 기능과 OS를 지원한다.

VMWARE 사이트에서 간단한 등록을 하면 리눅스용을 받을수 있다.
패키지는 rpm, bundle 2가지로 받을수 있으며 각각 x86, x64 버전이 있다.
우분투에 설치를 해야 되므로 .bundle 패키지를 받도록 한다.

패키지를 다운로드 받았으면 터미널에서 해당 패키지를 받은 폴더로 이동하여
'chmod 755 파일명' 을 통하여 실행이 가능하도록 변경을 한다.
그리고  'sudo sh ./파일명'을 실행하면 다음과 같은 창을 볼수 있다.
라이센스에 동의 하고 다음으로 넘어가도록 한다.


vmware에서 문제가 발생하였을때 사용할 Debugger을 설정하는 부분이다.
Eclipse가 설치되어 있어 그 경로가 자동으로 입력되었다. 설정이 안되어도 상관은 없다.

설치를 위한 준비가 모두 끝났으니 Install을 눌러 설치를 진행하도록 하자.

프로그래스 바가 슉~하고 지나가면서 설치를 하고 있다.

프로그래스바의 진행이 모두 완료된후 설치가 성공적으로 되었다는 메세지를 보여주고 있다.

메뉴바의 '프로그램 / 시스템 도구 / WMware Workstation' 을 실행하도록 한다.
라이센스에 관한 것이 나오는데 Accept를 선택하고 넘어가도록 한다.

VMware Workstation가 수행된 화면이다. 윈도우 VMware Workstation 같은 화면을 가지고 있다.

VMware Workstation을 설치하면서 같이 설치되는 것으로
Virtual Network Editor, VMware Player 도 모두 윈도우 환경과 동일하게 설치된다.
'프로그램 / 시스템 도구' 에서 찾아볼수 있다.

출처 : http://crazyits.tistory.com/tag/bundle

+ Recent posts