가용메모리 확보를 위한 안드로이드의 메모리 정책 및 ICS의 멀티태스킹 by regen

넥서스 포럼 카페에 썼던 글 백업 글입니다.

--------------------------------------------------------------------------------------

일단 이 글은 제가 자유수다란에 썼었던 두 게시물을 통합 정리한 글입니다. 중요한 부분 및 결론은 굵은 글씨로 강조해놓았으니 이해가 안가시면 그부분만 알아두셔도 됩니다. 이 글을 통해서 안드로이드가 가용메모리를 확보하기 위해서 어떤 작업 및 기능을 수행하는지 짚어보도록 하겠습니다.


현대 컴퓨터의 근간을 이루고 있는 구조는 폰노이만 컴퓨터 구조입니다. 몇몇 실험적인 특수목적의 컴퓨터를 제외하고 거의 대부분의 컴퓨터는 이 폰노이만 구조를 따르고 있습니다. 폰노이만 구조는 프로그램이 메모리(이 글에서의 메모리는 RAM을 지칭하도록 하겠습니다.)에 적재되어 CPU가 연산처리, 수행되는 구조를 일컫습니다. 안드로이드폰 또한 예외없이 폰노이만 구조를 따르는 컴퓨터의 범주안에 들어갑니다.


하지만 여기서 의문이 생깁니다. 폰노이만 구조에 따르면 실행되는 프로그램은 반드시 메모리에 올라가있어야 합니다. 하지만 기기가 가지고 있는 물리적인 메모리보다 프로그램의 크기가 더 크다면 어떻게 될까요? 예를 들어보겠습니다. 안드로이드의 대표적인 게임중 하나인 아스팔트6만 해도 총 프로그램의 크기는 1GB를 웃돕니다. 이런 크기의 프로그램이 물리적 메모리가 512MB인 넥서스S에 올라갈 수가 없습니다. 다행히도 현대 컴퓨팅 기술은 프로그램에서 당장 필요로하는 프로그램의 일부만 메모리에 올려서 실행할 수 있습니다. 그러다가 실질적으로 추가 데이터가 필요로 하게 되면 그 부분을 추가로 메모리에 올리게 되는 거죠.


하지만 프로그램 전체가 메모리에 올라갈 필요가 없다고는 해도, 메모리에 올라가게 되는 프로그램의 크기가 가용메모리 이상을 요구로할 때가 많습니다. 그렇기 때문에 안드로이드는 계속해서 필요이상의 가용메모리를 확보해야합니다. 안드로이드는 두가지 과정을 통해서 프로세스가 구동되는데 필요한 메모리를 확보합니다.


(1) life cycle에 따른 oom_adj 값에 따라 oom_killer 가 메모리에 올려져있는 프로세스를 제거하여 가용메모리를 확보.

(2) GC(garbage collector)를 통한 메모리 확보.


일단 (1) 에 대한 설명을 먼저 하겠습니다.


작년에 제 블로그에 쓴 '안드로이드의 메모리 정책 및 가용램(http://regen.egloos.com/4517293)' 이라는 글입니다. 자세한 내용은 이쪽에 언급되어 있으니, 추가적인 설명이 필요하신 분은 위 링크를 참조하시면 됩니다. 아래에는 위 글에 대한 간단한 내용을 요약하겠습니다.


안드로이드의 프로세스는 총 6개의 life cycle 상태를 지닙니다. life cycle은 다음과 같습니다.


1) foreground app 

2) visible app 

3) secondary server 

4) hidden app 

5) content provider 

6) empty app


1)은 현재 포그라운드로 실행되고 있는 프로세스를 의미합니다. 즉 지금 눈앞에서 실행되고 있는 프로그램입니다.

2)는 지금은 화면에 보이지 않지만 언제든지 호출되어 실행될 수 있는 프로세스를 의미합니다. 대표적으로 키보드 앱이 있습니다.

3)은 service 상태로 돌아가는 프로세스를 의미합니다. 실시간으로 기기의 상태를 체크하고, broadcast message 등을 수신하여 동작하는 프로세스들이 대부분입니다. 각종 위젯 및 안드로이드의 푸시 서비스에 해당되는 C2DM을 이용하지 않는 메신저류 어플들이 서비스 형태의 프로세스로 수행됩니다.

4)는 종료되지 않은 채 홈키 등을 눌러 백그라운드로 전환된 프로세스를 의미합니다.

5)는 안드로이드의 가장 큰 장점이자 특징 중의 하나인 컨덴츠 프로바이더입니다. 안드로이드는 앱간의 데이터 전송이 컨덴츠 프로바이더를 통해 이루어집니다. 이부분은 추후 컨덴츠 프로바이더의 효용성에 대해서 따로 글을 써보도록 하겠습니다.

6)은 캐쉬형태의 앱입니다. 유저가 실행하지 않았음에도 불구하고 안드로이드는 실행 빈도수가 잦은 앱을 우선순위로 캐쉬형태의 프로세스로 램에 올려두어 다음에 실행할 때 빠른 실행이 되도록 돕습니다.


각 사이클의 프로세스는 각각 다른 oom_adj 이란 숫자 값을 가지며 6) 에서부터 1) 로 갈수록 각각의 프로세스가 가지는 oom_adj 값은 작아집니다.


만일 다른 프로세스를 띄우거나 작동하는데 있어서 필요한 가용메모리가 부족할 경우 안드로이드는 정해진 메모리 정책에 의해서 oom_killer (outOfMemory_killer)가 작동하여 높은 oom_adj 값을 가진 프로세스부터 제거하여 필요한 가용메모리를 확보하게 됩니다.


안드로이드를 사용하다보면 실제로 많은 분들이 가용메모리에 집착하시는데 전 전혀 그럴 필요가 없다고 생각하고 있습니다. 특별한 경우(프로그램이 잘못 설계되어 메모리누수가 발생하는 등)를 제외하고는 태스크킬러류의 어플도 사용할 필요가 없다고 생각합니다. 뭐 물론 이에 대해서는 의견이 분분하긴 합니다만, 제가 태스크 킬러가 필요없다고 주장하는 이유는 이와 같습니다.


'태스크킬러 류의 어플이 필요없다고 주장하는 이유(http://regen.egloos.com/4556720)'


램은 확보하라고 있는 공간이 아니라 사용하라고 있는 공간입니다. 마냥 가용메모리가 확보가 많이 됐다고 좋은 건 아닙니다. 가용메모리가 잠시 높다한들 안드로이드는 메모리 정책에 따라 계속해서 캐시형태로 프로세스를 메모리에 올려둘테니까요. 뭐 어찌됐든 RAM은 사용하기 위한 공간입니다. 가용메모리가 적어서 퍼포먼스가 하락되는 경우는, 캐쉬형태가 아닌 실제로 작동되는 service나 종료되지 않은 background 프로세스가 많은 경우와, 덩치가 큰 프로세스를 띄움(대표적으로 3D게임등)에 따라 GC(garbage collector)가 작동했을 경우입니다.


사실 이도 GC의 성능이 미약했던 이클레어(2.1) 시절이라면 모를까 GC가 대폭 개선된 프로요(2.2) 부터는 사실상 태스크킬러 어플을 사용하지 않아도 사용하는데 큰 지장이 없습니다.


여기까지가 (1) oom_killer 에 의한 메모리 확보 과정입니다. oom_killer 를 통한 가용메모리 확보는 프로세스 자체를 kill 하여 해당 프로세스가 차지하고 있던 메모리를 가용메모리로 반환하는 것에 목적을 두고 있습니다.


다음으로 설명할 것은 (2) GC(garbage collector)를 통한 메모리 확보 입니다.



실행되기 위해 메모리에 올라가는 프로그램은 스택영역, 코드영역, 힙영역으로 나뉘어져 메모리에 올라갑니다. 물론 물리적으로 나뉜 게 아니라 논리적으로 나뉘어져 있는 것에 불과합니다.


여기서 유의깊게 살펴야 하는 것이 힙영역인데, 프로그래머는 원하는 객체(이미지, 사운드와 같은 리소스든, 아니면 소스 객체든)를 메모리의 힙영역에 필요할 때 할당하고, 필요없을 때 제거합니다.


C/C++과 같이 GC가 없는 프로그래밍 언어는 불필요하게 된 객체를 메모리에서 반환하는 작업을 프로그래머가 수동으로 구현해야합니다. 이를 제대로 하지 않으면 힙 영역에 객체가 계속해서 쌓이게 되어 메모리에 올라간 프로세스의 크기가 계속 커지게되는... 이른바 메모리 누수현상이 발생하게 되는 겁니다.


하지만 안드로이드 어플리케이션 프로그래밍에 쓰이는 JAVA와 같이 GC가 존재하는 프로그래밍 언어는 힙영역에 할당된 객체를 수동으로 메모리에 반환할 필요가 없습니다. 그 작업을 GC(garbage collector)가 알아서 해주거든요. 이러한 작업 또한 GC(garbage collection)라고 합니다. 덕분에 프로그래머 입장에서는 편합니다.


간단하게 예를 들어보겠습니다.


  

카카오톡 프로세스의 크기를 살펴보시기 바랍니다. 왼쪽의 카카오톡은 실행한 뒤에 대화도 하고 이리저리 대화창에도 들어갔다가 나왔다가 친구목록도 보고 한 직후의 프로세스의 크기입니다. 21MB군요. 카카오톡 프로세스의 힙 영역에 이런저런 많은 객체가 올라가 있는 상황입니다.


오른쪽은 사진은 왼쪽으로부터 12분이 흐른뒤입니다. 그동안 카카오톡은 전혀 건드리지 않았습니다. 프로세스의 크기가 21MB에서 7.2MB로 줄어들었습니다. 이는 GC가 수행되어 카카오톡 프로세스 내의 당장 필요없다고 판단되는 쓰레기 값(garbage)를 메모리로 반환했기 때문에 크기가 줄어든 것입니다.


이런 GC는 지정된 일정주기, 또는 프로그램을 띄우기 위한 가용메모리가 부족하여 급하게 메모리확보를 필요로할  때 수행됩니다.


이렇게 안드로이드는 (1) oom_killer 와 (2) GC를 통해서 필요한 메모리를 확보합니다. (1)의 방식이 프로세스 자체를 kill 해서 메모리를 확보하는 것이라면 (2)는 프로세스내의 필요없는 값(garbage)을 메모리로 반환하여 메모리를 확보하는 방식입니다.


근데 GC는 사실 기기의 퍼포먼스와 밀접한 관련이 있습니다.


사실 안드로이드 기기가 버벅거리는 순간은 GC가 수행되는 동안이라고 봐도 무방합니다. GC 작업 자체가 각 프로세스 내에서 필요없다고 판단되는 garbage를 찾아내고 이를 메모리로 반환하는 작업이라 상당한 오버헤드(부하)를 불러일으킵니다. 모바일 기기처럼 컴퓨팅 파워가 약한 기기라면 더욱 그러하겠죠.

 

또한 GC는 설정된 값에 따라 일정주기로 수행되는데 너무 자주 수행된다면 가용메모리는 많이 확보되나, GC로 인한 오버헤드가 심해 기기가 느려지고, 너무 늦게 수행되면 가용메모리가 부족하여 계속 프로세스가 kill 당하는 악순환에 처합니다. 따라서 적당한 시기에 GC가 작동할 수 있도록 하는 것이 중요합니다. 이건 뭐 안드로이드가 알아서 하니 유저분들은 신경쓰실 것 없습니다.(커스텀롬 및 커널 등에 따라 GC를 수행하는 시점이 다르기도 합니다. 이건 커롬/커널을 제작하는 제작자가 별도로 임의로 값을 지정해 놓은 것입니다.) 참고로 메모리 부스터와 같은 어플이 유저가 임의로 GC를 수행시켜 메모리를 확보하는 앱입니다.


그런면에서 아이폰의 iOS 프로그래밍에 쓰이는 object-c 언어는 GC를 사용하지 않습니다. 덕분에 힙영역에 할당된 객체를 프로그래머가 누수가 없도록 꼼꼼하게 메모리에 반환하는 코딩을 해야겠지만, GC작업이 없기 때문에 그로인한 오버헤드도 존재하지 않습니다. iOS는 android 대비 디바이스가 동일 사양일 경우 쾌적한 성능을 보이는데, 이는 여러가지 이유가 존재하지만 GC 유무 또한 한몫을 합니다.


결론적으로 말씀드리자면 안드로이드는 oom_killer 외에도 GC를 통해서도 가용메모리를 확보한다. 하지만 GC 작업 자체가 오버헤드(부하)를 불러일으키므로 GC가 수행되는 동안에는 기기의 퍼포먼스가 저하... 즉 버벅거리는 것을 경험할 수 있게 된다. 입니다.


뭐 어찌됐든 여기까지는 메모리(RAM)에서의 GC에 대한 내용이었고, 모바일 디바이스의 storage(저장공간)로 활용되는 NAND flash에도 GC작업이 존재하는데 이는 메모리의 GC와는 좀 다른개념이라 다음 기회에 설명하도록 하겠습니다. 참고로 NAND flash 의 GC도 상당한 오버헤드가 발생하는데 이는 NAND flash의 숙명과도 같습니다.




번외. ICS 의 멀티태스킹

ICS에서 홈키를 꾹 누를 경우(갤럭시 넥서스의 경우는 아예 멀티태스킹 버튼으로 존재)할 경우 등장하는 멀티태스킹 메뉴입니다. 진져브레드(2.3)까지는 홈키를 꾹 누를경우 recent app이 뜨게 되었으나, ICS에서는 좀 달라졌습니다. 각 메뉴를 좌우로 스와이프 함으로써 해당 메뉴를 제거할 수 있는데, 이를 두고 단순 기록 삭제냐, 아니면 프로그램의 종료냐 하는 설왕설래가 있는 걸로 알고있습니다.


정확히 하자면 전통적인 의미의 프로그램 종료와는 좀 다릅니다. 그렇다고 단순 기록 삭제는 아닙니다. 해당 메뉴를 스와이프 를 하여 제거하면 해당 프로세스는 kill 되는 것이 아니라 액티비티가 초기화 되며 위에서 설명했던 6) empty_app 즉 캐쉬 형태의 프로세스로 남게 됩니다. 하지만 액티비티가 유지되지 않고 초기화 되기 때문에 사실상의 프로그램 종료라고 봐도 무방합니다. 캐쉬로 형태로 남게된 프로세스는 oom_killer에 의해서 언제든지 필요하면 메모리에서 가장 먼저 제거되니까요.


(액티비티란? 안드로이드 어플리케이션에서 화면을 구성하는 단위입니다. 윈도우즈의 창으로 생각하시면 이해하기 편합니다.)


그러니까 결론은 태스크킬러 같은 거 쓰면서 가용램에 집착하지 마시고, 프로그램 종료도 ICS라면 멀티태스킹 메뉴에서 스와이프 하는 것으로도 충분합니다. 태스크킬러를 쓰시는 것보다는 차라리 위의 1) ~ 6)의 life cycle 값을 수정하시길 권하는 바입니다.


추가팁. 참고로 ICS의 멀티태스킹에 나오는 메뉴의 화면은 해당 프로세스의 현재 상태를 나타내는 것이 아니라, 해당 프로세스가 1) 포그라운드에서 다른 상태의 life cycle로 전환되기 직전의 화면을 '캡쳐' 해 놓은 것에 불과합니다. 따라서 멀티태스킹 메뉴에 존재한다고 해서 해당 프로세스가 살아있는 것을 보장하는 것은 아닙니다. 오히려 요즘 1GB의 넉넉한 메모리 용량으로 나오는 기기들에 비해서 메모리가 부족한 넥서스S의 경우는 높은 확률로 이미 프로세스가 제거되어있을 수 있습니다.

공유하기 버튼

 

구글뮤직 mp3 재다운로드 지원 by regen


자신의 mp3, flac 파일을 20,000곡까지 업로드하여 스트리밍으로 음악을 들을 수 있는 서비스인 구글뮤직이 업로드했던 파일을 다시 재다운로드 할 수 있는 기능을 지원하기 시작하였습니다.

▲ 뮤직 매니저를 통한 다운로드 지원.

▲ 구글 뮤직 웹상에서도 앨범별, 곡별 다운로드가 가능합니다.

공유하기 버튼

 

아스팔트6 이제야 다 깼네요... by regen

별 4개 짜리도 있지만 어쨌든 커리어 100%를 달성했음으로 클리어한 걸로 치겠습니다. 아스팔트6 구매한 게 작년 3월인데 이제야 다 깼네요. 수시로 폰 갈아엎고, 데이터 백업을 안했더니... 커리어 7~80% 정도에서 항상 초기화되었다는 슬픈 전설... (하지만 난 전설따윈 믿지 않아)

좀 슬픈 사실은 작년 3월에 Gameloft 홈페이지에서 결제했는데 그뒤로 리인스톨을 위해서 다시 다운 받으면 마켓 최신판인 1.0.8버전이 오는 게 아니라 구버전이 온다는 사실... 1.0.8 버전과 구버전의 게임 퍼포먼스 차이가 꽤 있는지라 정품을 구매했음에도 불구하고 눈물을 머금고 크랙판 씁니다 (...)

Gameloft는 각성하라!

공유하기 버튼

 

구글맵 국내 스트리트뷰 서비스 시작 by regen

국내에서는 다음이 '로드뷰', 네이버가 '거리뷰'란 이름으로 서비스하고 있는 지도 사진 서비스를 구글맵에서도 국내에서 시작하였습니다. 구글의 스트리트뷰는 과거 서비스를 시작하기 위해 촬영작업을 하던 중 WIFI 개인정보 수집 논란에 휩싸여 잠정 중지된 바가 있습니다. 언제 시작할지 기약없던 것이 서울과 부산 인근을 포함하여 드디어 시작하였습니다. 빠른 시일내로 전국으로 확대되길 기대합니다.
▲ 웹상에서는 원하는 장소에 스트리트뷰 아이콘을 끌어다 놓으면 스트리트뷰가 뜨게 됩니다.

  
▲ 안드로이드 구글맵에서는 원하는 장소를 꾹 누르면 나오는 상세 정보에서 스트리트뷰를 활성화 할 수 있습니다.

구글맵은 이제 국내 스트리트뷰 서비스도 시작했으니 지도 데이터를 비트맵에서 벡터이미지로 전환하고 3D 건물 도입하면 되는데, 이건 국내법에 막혀있으니 아마 안되겠지...

공유하기 버튼

 

새해 복 많이 받으세요. by regen

새해 복 많이 받으세요. 두번 받으세요. 세번 받으세요. 또 받으세요. 가열차게 받으세요. 전 악랄하게 받을 겁니다.

그리고 신년맞이 서비스짤. 어차피 이 블로그는 남자만 오니까........

공유하기 버튼

 

1 2 3 4 5 6 7 8 9 10 다음


QR코드


QR Code

트위터공식위젯