아래는 어떤 문자열에 GSM7 문자셋에 포함되어 있지 않은 문자가 존재하는지 체크하는 메소드입니다. 프레임워크 라이브러리에 포함된 GsmAlphabet 클래스를 이용하고 있습니다.

    /**
     * GSM 이외의 문자가 포함되어 있는가?
     */
    public static boolean isNonGsmAlphabetExists(CharSequence  v) {
        try {
            com.android.internal.telephony.GsmAlphabet.countGsmSeptets(v, true);
        } catch (Exception e) {
            return true;
        }

        return false;
    }

Exception이 던져지는지 여부로 판단을 하기 때문에 성능상 좋은 소스는 아닙니다만, 저는 단순함을 좋아하기 때문에 별로 신경안씁니다.^^
더 효과적인 방법이 있는지는 모르겠습니다. 참고만 하세요.

Posted by 에코지오
,
안드로이드용 JVM인 Dalvik VM에는 여러가지 실행 옵션이 있습니다. dalvikvm -help 명령으로 가능한 옵션들을 볼 수 있습니다.

$ adb shell
# dalvikvm -help
dalvikvm -help

dalvikvm: [options] class [argument ...]
dalvikvm: [options] -jar file.jar [argument ...]

The following standard options are recognized:
  -classpath classpath
  -Dproperty=value
  -verbose:tag  ('gc', 'jni', or 'class')
  -ea[:<package name>... |:<class name>]
  -da[:<package name>... |:<class name>]
   (-enableassertions, -disableassertions)
  -esa
  -dsa
   (-enablesystemassertions, -disablesystemassertions)
  -showversion
  -help

The following extended options are recognized:
  -Xrunjdwp:<options>
  -Xbootclasspath:bootclasspath
  -Xcheck:tag  (e.g. 'jni')
  -XmsN  (min heap, must be multiple of 1K, >= 1MB)
  -XmxN  (max heap, must be multiple of 1K, >= 2MB)
  -XssN  (stack size, >= 1KB, <= 256KB)
  -Xverify:{none,remote,all}
  -Xrs
  -Xint  (extended to accept ':portable' and ':fast')

These are unique to Dalvik:
  -Xzygote
  -Xdexopt:{none,verified,all}
  -Xnoquithandler
  -Xjnigreflimit:N  (must be multiple of 100, >= 200)
  -Xjniopts:{warnonly,forcecopy}
  -Xdeadlockpredict:{off,warn,err,abort}
  -Xstacktracefile:<filename>
  -Xgc:[no]precise
  -Xgenregmap
  -Xcheckdexsum

Configured with: debugger profiler hprof show_exception=1

Dalvik VM init failed (check log file)

안드로이드 환경에서 우리는 dalvikvm 명령어를 실행하여 직접 애플리케이션 프로세스를 띄우지는 않습니다. 때문에 달빅 VM에 직접적으로 옵션을 전달할 수가 없습니다. 
그대신 안드로이드는 시스템 프로퍼티(system properties)를 설정하여 달빅 VM 실행옵션을 바꾸는 방법을 제공합니다. 간단하게는 setprop 명령어로 실행옵션을 바꿀 수 있습니다.
adb shell setprop dalvik.vm.[옵션명] [옵션값]

위와 같은 형식으로 달빅VM 관련 프로퍼티를 설정한 후, zygote 프로세스를 재시작하면(adb shell stop;adb shell start) 새로 런치되는 앱 프로세스에 변경사항이 적용됩니다.

VM 옵션에 대응하는 dalvik.vm.* 형식의 프로퍼티명이 정확히 무엇인지는 framework/base/core/jin/AndroidRuntime.cpp 소스를 참조하면 알 수 있습니다. 일단 제가 찾아낸 프로퍼티명과 프로퍼티값 샘플은 다음과 같습니다.

# -Xmx
dalvik.vm.heapsize

# -Xstacktracefile (기본값 /data/anr/traces.txt)
dalvik.vm.stack-trace-file 

# -Xcheck:jni (값은 true or false)
dalvik.vm.checkjni 

# -Xjniopts
dalvik.vm.jniopts

# -ea (값은 all, ?, ...)
dalvik.vm.enableassertions

# v=a,o=v와 같은 형식으로 값 설정
# v=a는 -Xverify:all, v=n은 -Xverify:none, v=r은 -Xverify:remote에 해당
# o=a는 -Xdexopt:all, o=v는 -Xdexopt:verified, o=n은 -Xdexopt:none에 해당
# m=y는 -Xgenregmap -Xgc:precise에 해당
dalvik.vm.dexopt-flags

# -Xint (값은 int:portable or int:fast or int:jit)
dalvik.vm.execution-mode 

# -Xdeadlockpredict
dalvik.vm.deadlock-predict

# -Xcheckdexsum (값은 true or false)
dalvik.vm.check-dex-sum 

# -Xthreshold
dalvik.vm.jit.threshold

# -Xjitop
dalvik.vm.jit.op

# -Xincludeselectedop
dalvik.vm.jit.includeop

# -Xjitmethod
dalvik.vm.jit.method 

# -Xincludeselectedmethod
dalvik.vm.jit.includemethod 

# -Xjitprofile
dalvik.vm.jit.profile  

* 자세한 내용은 다음 문서를 참조하시기 바랍니다.
Posted by 에코지오
,
가끔씩 마주치게 되는 "OutOfMemoryError : bitmap size exceeds VM budget" 에러는 메모리 누수가 주요 원인입니다. 이와 관련된 링크를 모아봤습니다.

* 액티비티가 멈출 때 비트맵을 재활용(즉 GC)되게 하라

- bitmap 이미지인 경우 recycle() 호출
- onPause에서 수행하는게 좋음
- ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();

* 이미지를 미리 줄여서 읽어들여라

- BitmapFactory.Options.inSampleSize 활용

* Activity Context에 대한 참조(reference)를 오랫동안 유지하지 말아라

- Drawable.setCallback(null) 사용
- WeakReference를 가진 static 내부 클래스
- 이미지를 static 변수로 처리하지 마라

* 외부(outer) 클래스의 상태에 의존하지 않는 내부(inner) 클래스는 static으로 선언하라
- 내부클래스는 외부 클래스 인스턴스를 크게 만들며 또한 외부클래스 객체가 필요이상으로 오래 살아있게 되어 메모리를 더 차지할 수 있음
- 외부클래스의 상태 필드에 접근하지 않는(즉 외부 객체의 상태에 의존하지 않는) 내부클래스는 static으로 선언

* Attacking memory problems on Android

Posted by 에코지오
,
어떤 어플리케이션 프로세스가 복잡한 작업으로 인해 과도하게 CPU를 점유하게 되면, 사용자가 다른 어플을 사용하다가 ANR을 만나게 될 가능성이 큽니다. 구글링해본바 CPU 점유율을 낮추기 위한 일반적인 방법은 아래 2가지로 요약됩니다.

1. 쓰레드 우선순위 낮추기
다음 코드를 통해서 쓰레드의 우선순위를 낮춰줍니다.
 
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

그러나 이미 백그라운드로 실행되도록 작성됐다면 효과는 미지수입니다.


2. 중간중간 쓰레드를 쉬게함
반복적인 계산의 경우 반복작업 사이사이 짧은간격으로 Thread.sleep(milisenconds) 메소드를 이용하여 쓰레드를 쉬게합니다. 
200ms 일하고 100ms 쉬고, 이런식으로 처리 시간은 다소 길어지더라도 사용자가 감내 가능한 최적의 sleep 텀을 찾아냅니다.


* 내용추가(2010/08/23)
3. 구글 동기화 어플에서 사용하는 전략
구글 동기화 어플에서는 현재 CPU 점유율에 따라서 동적으로 작업을 조정해서 처리한다고 합니다. 예들들어, 현재 CPU의 IDLE 상태 비율(즉 놀고있는 비율)을 계산해서 IDLE이 높으면 작업을 많이 처리하고, 낮으면 적게 처리합니다. 그리고 IDLE 비율이 너무 낮으면(다른 프로세스들이 CPU를 많이 쓰고 있으면) 작업을 중단하고 잠시 쉬었다가 다시 시도합니다. 

Posted by 에코지오
,
소스를 디버깅하다 보면 분명 SQLiteCursor의 finalize 메소드 코드에 중단점(break point)를 걸지 않았음에도 불구하고 자꾸 브레이크가 걸리는 경우가 있습니다.


저는 처음에 이 현상의 원인이 프레임워크 라이브러리 빌드시 어떤 식으로든 중단점 정보가 잘못 포함되어 걸리는 줄로 짐작하고 대수롭지 않게 생각했습니다. 근데 그게 아니더군요. 구글신에게 물어보니 아래와 같은 답변이 나왔습니다.

The implication is that you haven't used cursor.close() and left an 
"open" cursor around when your activity/service was destroyed.   You 
either need to do this manually, or make sure you're using a managed
cursor. 

If you're not using a managed cursor, you should wrap every cursor 
creation with a try/finally expression. 

그러니까 코드 어딘가에 close 되지 않은 커서가 있는 것이니 명시적으로 finally절에서 close해줘야 한다는 겁니다. 불행히도 close 되지 않은 커서가 어느 클래스의 어느 메소드에서 open 됐는지는 디버깅 창의 스택트레이스에 나와있지 않습니다. 

하지만 한가지 힌트는 있습니다. SQLiteCursor 객체의 mQuery 멤버변수에는 해당 커서가 실행했던 쿼리 정보가 담겨 있습니다. 이 쿼리를 Variables 창에서 확인할 수 있습니다. 이제 close되지 않는 커서가 실행했던 쿼리가 무엇인지 알았으니 대충 소스의 어느 부분에서 open된 건지 찾아낼 실마리를 얻은 겁니다.


* 내용추가(2010/08/12)
cursor가 어느 클래스의 어느 메소드에서 open 된 것인지 로그캣에 출력할 수 있습니다. SQLiteCursor.finalize()의 아래 코드에 방법이 나옵니다.

if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
    Log.d(TAG, message + "\nThis cursor was created in:");
    for (StackTraceElement ste : mStackTraceElements) {
        Log.d(TAG, "      " + ste);
    }
}

즉 SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION 이 true이면 스택트레이스를 DEBUG 레벨로 로깅해줍니다. 
DEBUG_ACTIVE_CURSOR_FINALIZATION 을 true로 설정하는 방법은 Log.isLoggable() 메소드에 나오는 아래 설명을 참조하여,
Checks to see whether or not a log for the specified tag is loggable at the specified level. The default level of any tag is set to INFO. This means that any level above and including INFO will be logged. Before you make any calls to a logging method you should check to see if your tag should be logged. You can change the default level by setting a system property: 'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>' Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPRESS will turn off all logging for your tag. You can also create a local.prop file that with the following in it: 'log.tag.<YOUR_LOG_TAG>=<LEVEL>' and place that in /data/local.prop.
다음처럼 명령을 날립니다.

$ adb shell
# setprop log.tag.SQLiteCursorClosing VERBOSE

이제 로그캣에 닫히지 않은 커서의 스택트레이스가 나올 것입니다. (그러나 저는 안나오더군요. 왜 안나오는지 모르겠습니다.ㅠㅠ)

이 방법을 응용하여 SQLite가 실행하는 모든 쿼리를 로그캣에 찍을 수 있습니다.
android.database,sqlite.SQLiteDebug 클래스의 DEBUG_SQL_STATEMENTS 옵션을 한번 볼까요.

    /**
     * Controls the printing of SQL statements as they are executed.
     */
    public static final boolean DEBUG_SQL_STATEMENTS =
            Log.isLoggable("SQLiteStatements", Log.VERBOSE);

아하 "SQLiteStatements" 군요. 아래의 명령어를 실행해주면 모든 쿼리가 로그캣에 디버그 레벨로 로깅됩니다.

$ adb shell
# setprop log.tag.SQLiteStatements VERBOSE

Posted by 에코지오
,
쓰레드 덤프는 프로세스에서 실행중인 쓰레드들의 스냅샷입니다. 쓰레드 덤프를 통해서 덤프시점에 현재 어떤 쓰레드들이 있는지, 쓰레드들의 상태는 어떤지, 쓰레드가 어떤 메소드를 실행하며 지나왔고 어떤 메소드를 실행중인지 파악할 수 있습니다.

1. DDMS 쓰레드 뷰
안드로이드는 DDMS를 통해서 쓰레드 스택을 쉽게 분석할 수 있게 지원합니다.

(1) DDMS에서 프로세스를 선택후 Update Threads 아이콘을 클릭합니다. 
(2) 오른편 Threads 탭에 선택된 프로세스의 쓰레드 목록이 나타납니다.  
(3) 쓰레드를 한개 선택하고 Refresh 버튼을 누르면 그 순간의 쓰레드스택(쓰레드가 실행한 객체 메소드) 정보가 나타납니다.


Threads 목록의 각 컬럼에 대한 설명은 다음과 같습니다.
  • ID : VM 내의 쓰레드 ID. DVM의 경우 3부터 시작하는 홀수. 앞의 별표는 데몬(daemon) 쓰레드.
  • Tid : 리눅스 쓰레드 ID. main 쓰레드의 경우 프로세스 ID와 일치.
  • Status : 쓰레드 상태 
running - executing application code(실행중)
sleeping - called Thread.sleep() 
monitor - waiting to acquire a monitor lock(다른 쓰레드가 작업을 마치기를 기다리는 중)
wait - in Object.wait() 
native - executing native code 
vmwait - waiting on a VM resource 
zombie - thread is in the process of dying 
init - thread is initializing (you shouldn't see this) 
starting - thread is about to start (you shouldn't see this either) 

  • utime : 사용자 코드 누적 실행시간. cumulative time spent executing user code, in "jiffies" (usually 10ms). 
  • stime : 시스템 코드 누적 실행시간. cumulative time spent executing system code, in "jiffies" (usually 10ms). 
  • Name : 쓰레드 이름

의미있는 스택 트레이스 정보를 보기 위해서는, 단말의 기능을 사용하면서 순간을 잘 포착하여 Refresh 버튼을 눌러야 트레이스를 제대로 볼 수 있습니다. 때를 놓치면 이미 실이 지나가고 난 뒤의 고요한 트레이스만 보이게 됩니다. ^^
애플리케이션이 응답 없음 상태(ANR)일 때 Refresh 버튼을 눌러, 도대체 쓰레드가 현재 어떤 메소드를 실행 중이길래 반응이 없는 건지 알 수 있을 것으로 보입니다. 또한 락(lock)이 걸렸을 때 이것이 쓰레드 경합(monitor 상태의 쓰레드들)에 의한 문제인지 파악할 수 있을 것으로 보입니다. (그러나 2경우 모두 아직 이런 식으로는 확인 못해봤습니다.-.-; )

2. /data/anr/traces.txt
애플리케이션에 에러가 발생해서 프로세스가 죽게 되면 달빅 VM은 보통의 JVM처럼 자동으로 쓰레드덤프(javacore) 파일을 떨궈줍니다.  "/data/anr/traces.txt" 파일이 그것입니다. 
아래는 애플리케이션 에러로 애플리케이션이 중지되는 시점의 로그입니다. 맨 아랫줄을 보시면 스택트레이스가 "/data/anr/traces.txt" 파일에 쓰여진다는 정보를 볼 수 있습니다.


경우에 따라서는 애플리케이션 프로세스가 "/data/anr/traces.txt" 파일에 쓰기 권한이 없어서(permission denied) traces.txt에 기록을 못할 수도 있습니다. 하지만 꼭 traces.txt가 아니더라도 위에 나오듯이 로그캣에 친절하게 Exception 스택 트레이스 정보가 나오기 때문에 에러 분석에는 큰 문제가 없을 것입니다.

쓰레드 덤프는 사용자가 직접 kill -3 <PROCESS ID> 명령을 날려서 만들 수도 있습니다. ANR이 발생하거나 lock이 걸리면 이렇게 쓰레드덤프를 떠야겠죠. 참고로, /data/anr/traces.txt 파일은 매번 새로 생성되지 않고 기존 파일에 쓰레드 덤프가 누적되어 기록됩니다. 아래는 쓰레드 덤프 파일에 기록된 내용의 예입니다.

----- pid 224 at 2010-02-12 05:41:20 -----
Cmd line: com.example.android.notepad

DALVIK THREADS:
"main" prio=5 tid=3 WAIT
  | group="main" sCount=1 dsCount=0 s=N obj=0x4001b268 self=0xbd00
  | sysTid=224 nice=0 sched=0/0 cgrp=default handle=-1344001384
  at java.lang.Object.wait(Native Method)
  - waiting on <0x14c328> (a android.os.MessageQueue)
  at java.lang.Object.wait(Object.java:288)
  at android.os.MessageQueue.next(MessageQueue.java:148)
... 중략 ...
  at java.lang.reflect.Method.invoke(Method.java:521)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
  at dalvik.system.NativeStart.main(Native Method)

"Binder Thread #1" prio=5 tid=11 NATIVE
  | group="main" sCount=1 dsCount=0 s=N obj=0x43cfb248 self=0x134170
  | sysTid=228 nice=0 sched=0/0 cgrp=default handle=1259984
  at dalvik.system.NativeStart.run(Native Method)

"JDWP" daemon prio=5 tid=9 VMWAIT
... 중략 ...
"Signal Catcher" daemon prio=5 tid=7 RUNNABLE
... 중략 ...
"HeapWorker" daemon prio=5 tid=5 VMWAIT
... 중략 ...
----- end 224 -----

* 일부 내용에 오류가 있을 수 있습니다.
Posted by 에코지오
,

안드로이드 Resources, Assets, R 클래스에 대해 간단히 알아봅니다.

1. Resources

  • 리소스는 애플리케이션이 필요로 하는 코드 이외의 자원
  • 이미지, 오디오, 비디오, 텍스트 문자열, 레이아웃, 테마 등
  • 리소스는 res/ 폴더에 위치시킴
  • 리소스 파일명은 소문자, 숫자, 마침표(.), 언더바(_)로만 구성
  • 리소스는 빌드타임에 안드로이드 빌드시스템에 의해 감지되며, 각 리소스는 고유의 ID를 부여받음
  • 안드로이드는 리소스ID를 포함하는 R 클래스를 생성해줌(aapt)
  • 리소스는 Resources 인스턴스를 통해 액세스됨
  • 리소스는 빌드시 컴파일되어 애플리케이션 바이너리에 포함됨


2. Assets

  • Resources와 비슷하나 자주 사용되지 않음
  • assets/ 폴더에 위치함
  • 어떤 종류의 파일이든 가능
  • 컴파일되지 않고 원시형태 그대로(raw) 패키징됨
  • 바이트스트림(InputStream) 형식으로 읽기 가능
  • 파일시스템의 파일처럼 다루어짐(리소스ID 없음)
  • AssetManager를 이용


* 파일 시스템처럼 다루어진다는 의미
 - 파일목록을 구할 수 있고 순회할수 있고 원하는 파일을 찾을 수 있다(listed, iterated, discovered)

* 하위 디렉토리 구조
 - Assets 디렉토리(assets/)는 하위 디렉토리 구조(hierachy)를 유지할 수 있다.
 - Resources 디렉토리(res/)는 하위 디렉토리 구조를 가질 수 없다(R 클래스에 나타나지 않게됨)
 
* res/raw/ 폴더와 assets/ 폴더의 차이점
 - 리소스ID가 있는가 없는가
 - Resources를 이용하는가 AssetManager를 이용하는가
 - 그 외 큰 차이없는 듯

3. R 클래스
안드로이드는 애플리케이션 소스코드에서 리소스 ID를 쉽게 참조할 수 있게 aapt(android asset packaging tool)를 이용하여 R클래스를 자동으로 만들어서 제공합니다.

 

R 클래스의 구조는 다음과 같습니다.

참고로 framework-res.apk에 포함된 시스템 리소스들의 ID는 android.R 클래스에 정의되어 있습니다.

Posted by 에코지오
,
자바 프로세스에서 어떤 객체들이 얼만큼의 메모리를 점유하고 있는지 알아내기 위해 우리는 Heap 메모리를 분석합니다. 
안드로이드에서는 달빅 VM의 힙 메모리를 3가지 수준에서 분석할 수 있습니다. 

1. 개략적인 수준 - DDMS의 VM Heap 탭



아주 간략히 힙 메모리 통계 정보를 보여줍니다. Total/Allocated/Free 메모리 크기, 주요 타입별 객체 갯수 및 크기를 알 수 있습니다. 이게 전부입니다. 아쉽지만 특정 객체를 꼭 찝어서 할당된 갯수와 크기를 알 수는 없습니다. 
그렇지만 메모리 누수가 의심될 때 실제로 누수인지 아닌지 간단하게 판단하는 용도로 활용할 수 있어보입니다. 의심되는 구간에 대해서 [Cause GC] 버튼을 눌러도 객체들이 GC되지 않고 계속해서 쌓인다면 메모리 누수를 의심할 수 있습니다. (안드로이드에서도 GC log 분석이 된다면 gc 로그를 분석하여 메모리 누수 여부를 판별할 수 있겠지만 제가 아직까지 이 방법을 찾지못했습니다)


2. 약간 상세한 수준 - DDMS의 Allocation Tracker 탭



Allocation Tracker는 트래킹을 시작한 이후로 새롭게 할당된 객체들 정보를 비교적 상세히 볼 수 있습니다. Allocation Tracke 사용에 대한 자세한 내용은 Tracking Memory Allocations 기사를 참고하시면 됩니다.(한글 번역 : http://blog.naver.com/huewu/110082424176)


3. 아주 상세한 수준 - Eclipse Memory Analyzer



전문가 수준으로 힙 메모리를 파악하기 위해서는 힙 덤프를 생성해서 분석해야 합니다. 현존 최고의 무료 자바 힙메모리 분석 도구는 아마 Eclipse Memory Analyzer(MAT)일 겁니다. MAT는 힙 분석을 위한 너무나 방대하고 다양한 기능을 제공하기 때문에 제가 감히(?) 여기서는 사용법을 설명드리지 않겠습니다. -.-;; 자세한 사용법은 MAT 공식 사이트나 Eclipse Memory Analyzer, 10 useful tips/articles 를 참고하시기 바랍니다(실토하자면 MAT는 저도 제대로 사용해보질 못했습니다. 머리 싸매고 힙 분석할 일이 아직 없네요. 문제 생기면 그때 공부하렵니다 ㅎㅎ).

ps. 어째 글이 점점 성의가 없어지는 거 같네요. 하핫.
Posted by 에코지오
,
1. adb 이용
- 먼저 root 권한이 있는지, /data/misc에 쓰기 권한이 있는지 확인합니다.
- shell로 들어가서 해당 프로세스에 SIGUSR1 시그널을 날리면 힙덤프 파일이 떨궈집니다.

$ adb shell
# mkdir /data/misc
# chmod 777 /data/misc (/data/misc에 쓰기권한 확인)
# ps (애플리케이션 프로세스 ID 확인)
# kill -10 <pid> (SIGUSR1 시그널 전송)

(잠시후 /data/misc 에 heap-dump-*.hprof 파일 생성됨)

$ adb pull <dump-file> <as-file> (로컬로 파일 추출)


2. API 이용
- android.os.Debug 클래스의 public static void dumpHprofData(String fileName) 메소드를 호출합니다.
- 단, fileName은 쓰기 권한 있는 경로를 지정해야합니다.


3. DDMS 이용 


- 애플리케이션에 WRITE_EXTERNAL_STORAGE 퍼미션이 설정됐는지 확인합니다.
- sdcard가 있고, sdcard에 쓰기 권한이 있는지 확인합니다.
- 해당 프로세스 선택후 위 그림에서처럼 힙덤프 버튼을 누르면 /sdcard 경로에 <패키지>.hprof 파일이 생성됩니다.


힙덤프 파일 포맷 변경
위 세가지 방법으로 생성한 힙덤프 파일은 Dalvik VM 고유의 포맷을 가집니다. 안드로이드 SDK에 포함된 hprof-conv.exe를 이용하여 표준 hprof 포맷으로 변경할 수 있습니다.

$ hprof-conv.exe <달빅 hprof 파일> <표준 hprof 파일>

이렇게 변경된 hprof 파일은 jhat이나 Eclipse Memory Analyzer(MAT) 같은 Heap 덤프 분석툴을 이용하여 시각적으로 분석할 수 있습니다.
Posted by 에코지오
,
프로세스 : 문제식별 -> 데이터 수집 -> 데이터 분석 -> 가설설정 -> 원인분석 -> 개선방안 -> 해결조치


문제해결 접근방식
  • Divide&Conquer 분석 : 문제를 작은 구간으로 나누어서 분석
  • Event 분석 : log,dump,trace 등 각종 기록 분석
  • Queue 분석 : 자원(cpu/network/memory/connection 등)의 대기행렬 분석. 병목파악

Event 분석
  • log : 시점별 이벤트. history
  • dump : 특정 시점의 리소스 상태. snapshot
  • trace : 리소스 활동상태 추적. profiling

안드로이드에서 주로 발생하는 문제
  • 애플리케이션 응답없음(ANR)
  • 시스템 응답없음(먹통, lock up)
  • 프로그램 오류
  • 낮은 성능
  • Crash
     => 경험에 의한 자료 부족

주요 원인
  • bug : 애플리케이션 오류
  • resource leak : 메모리 누수, 자원미반납 등
  • bottleneck : 디스크 IO 병목? 네트워크 병목?
  • dead lock : 쓰레드 경합
  • bad query : Provider의 악성 SQL
  • unoptimized : 튜닝 안된 파라미터 설정
     => 경험에 의한 자료 부족

분석 방법
  • 힙덤프 분석
  • 쓰레드 분석
  • 가용자원 분석
  • 프로파일링
  • IO 병목 분석
  • 네트워크 분석
  • 소스 디버깅
  • 로그 분석
  • 파일/데이터(DB) 분석

주요 도구
  • ADB
  • logcat
  • TraceView
  • DDMS
  • Eclipse ADT
  • Eclipse MAT
  • 쉘 명령어 : ps, top, ...

데이터 수집

1. 시스템 정보수집 : 분석의 기본
- SW, HW, 네트워크 정보수집
- cpu,memory,network,disk 등 장치 및 kernel 정보
- 리소스 사용량

2. 특정시점의 자원/상태 정보 : 정적 데이터, snapshot, dump
- 힙메모리 덤프 : kill -10 <pid>
- 쓰레드 덤프 : kill -3 <pid>, /data/anr/traces.txt
- App 상태 정보 : dumpsys
- Device 상태 정보 : dumpstate
- 무선연결 정보 : DDMS > Dump radio state

3. 시스템의 활동상태/이벤트 정보 : 동적 데이터, tracing, monitoring
 - 이벤트 로그(히스토리 분석) : logcat
 - 실행 기록(동적활동 추적) : DDMS > Start Method Profiling
 - 리소스 모니터링 : vmstat, top, ...


문제의 사전예방
  • FindBugs : 잠재된 소스오류 검출
  • JUnit : 단위 테스트
  • Monkey : 스트레스 테스트, 랜덤 이벤트 발생
  • Best Practice 준수
Posted by 에코지오
,