<안드로이드/Android> 안드로이드에서 프로세스란?

Posted by 앱해피
2015. 6. 20. 14:57 안드로이드 이론

 

안드로이드에서 프로세스(Proces)와 스레드(Thread)

 

어플리케이션 컴포넌트(구성요소)가 시작될 때, 그리고 현재 어플리케이션에서 실행되고 있는 컴포넌트가 하나도 없을 때, 안드로이드 시스템에서는 해당 어플리케이션을 위해 하나의 스레드로 구성된 프로세스를 시작시킨다.

 

기본적으로, 같은 어플리케이션 내에 있는 모든 컴포넌트는 동일한 프로세스, 즉 "메인 스레드"라 불리는 스레드에서 동작한다.

 

어플리케이션 컴포넌트(구성요소)가 이제 막 시작할 때, 애플리케이션에서 이미 프로세스가 존재하고 있다면 새로 시작한 컴포넌트는 그 프로세스에서 컴포넌트가 실행된다. 하지만, 어플리케이션에 존재하는 여러 컴포넌트들이 서로 다른 프로세스에서 동작하도록 재배치할 수도 있다. 그 뿐 아니라 프로세스에 다른 스레드도 생성할 수 있다.

 

안드로이드 어플리케이션에서 동작하는 프로세스와 스레드에 대해 알아보자.

 

프로세스(Process)

 

기본적으로, 안드로이드 앱을 구성하는 모든 컴포넌트들은 동일한 프로세스에서 동작하도록 구성되어 있다. 그리고 대부분의 어플리케이션에서는 이를 변경하지 않아야 한다.

 

하지만, 어플리케이션에서 특정 컴포넌트를 다른 프로세스에서 실행시키고 제어하기 위해서는 매니페스트 파일에 별도로 그와 관련된 설정을 해야한다.

 

<activity>, <service>, <receiver> 그리고 <provider>와 같은 컴포넌트 요소들과 관련된 매니페스트 항목은 android:process라는 속성을 이용해서, 해당 컴포넌트가 동작할 프로세스를 명시할 수 있다.

 

이 속성값을 활용해서 각각의 컴포넌트를 애플리케이션 자체에서 제공하는 프로세스에서 동작시킬 수도 있고 아니면 다른 프로세스에서 동작시킬 수도 있다.

 

이와 같은 방식으로 일부 컴포넌트는 프로세스를 공유하지만 다른 컴포넌트들은 프로세스를 공유하지 않게 만들 수 있다. 그뿐 아니라, android:process 속성을 설정해서 서로 다른 애플리케이션에 있는 컴포넌트들을 동일한 프로세스에서 실행되게 할 수 있다.

 

<application> 요소 역시도 android:process 속성을 지원해서, <application> 요소 밑에 존재하는 모든 컴포넌트들의 android:process 기본 속성값을 일치시키게 된다.

 

안드로이드 시스템에서는 메모리가 부족한 특정 시점에서 현재 사용되고 있지 않는 프로세스를 종료한다. 이 때, 종료되는 프로세스에 존재했던 모든 컴포넌트들은 차례로 종료가 된다.

 

이후, 종료된 프로세스와 관련된 작업을 다시 수행해야 할 때, 안드로이드 시스템은 해당 프로세스를 다시 실행한다.

 

종료시켜야 할 프로세스를 결정할 때, 안드로이드 시스템에서는 유저의 입장에서 각각의 프로세스에 가중치(우선순위)를 매긴다.

 

예를 들면, 현재 유저가 보고 있는 액티비티보다는 더 이상 유저와 관련이 없는 액티비티가 종료될 가능성이 더 크다.

 

어떤 프로세스를 종료시킬 것인가 결정하는 과정은 프로세스에서 현재 동작하고 있는 컴포넌트의 상태에 따라 결정된다. 어떤 프로세스를 종료할 것인가와 관련된 규칙은 아래와 같다.

 

프로세스 라이프사이클(Process lifecycle)

안드로이드 시스템은 가능한 오래 어플리케이션 프로세스를 유지시키기 위해 노력한다, 하지만 새로운 프로세스가 사용될 메모리가 부족할 때나 또는 더 중요한 프로세스가 실행되어야 하는 상황에서는 기존에 중요하지 않는 프로세스는 종료해야 할 필요성이 있다.

 

어떤 프로세스를 살리고 혹을 죽일지 결정할 때, 시스템에서는 컴포넌트의 상태와 프로세스에서 실행되고 있는 컴포넌트를 기초로 해서 각각의 프로세스에 "중요도 계층"를 할당한다.

 

"중요도 계층"에는 5개의 레벨이 존재한다. 아래에 나와 있는 리스트는 "중요도"와 관련된 서로 다른 유형의 프로세스를 보여준다.(가장 중요한 프로세스부터 - 중요하지 않은 프로세스까지)

 

(1) Foreground process

 

현재 유저가 사용하고 있는 프로세스다. 아래에 있는 조건이 충족될 때, 프로세스는 Foreground 상태에 놓여 있다고 간주된다.

 

* 스마트폰 유저와 상호 동작되고 있는 화면(액티비티)은 Foreground 프로세스에 속한다.

 

* 현재 스마트폰 유저가 보고 있는 화면과 결속(Binding)되어 있는 서비스는 Foreground 프로세스에 속한다.

 

* startForeground()이용해서 호출한 프로세스는 Foreground 프로세스에 속한다.

 

* onCreate(), onStart() 또는 onDestroy()를 콜백함수 중 하나를 실행하고 있는 서비스는 Foreground 프로세스에 속한다.

 

* onReceive() 함수를 호출하고 있는 브로드캐스트 리시버는 서비스는 Foreground 프로세스에 속한다.

 

(2) Visible process

 

Foreground 컴포넌트에 해당하지 않는 프로세스이나, 여전히 스마트폰 화면을 통해서 볼 수 있는 컴포넌트에 해당한다. 아래에 나와있는 조건이 충족될 때, 프로세스는 Visible(눈에 보이는) 것으로 간주된다.

 

* Foreground 상태에 놓여있지 않는 액티비티이나, 사용자가 여전히 화면(액티비티를)을 볼 수 있는 조건에 해당한다. 이와 관련된 예는, 만약에 Foreground 액티비티에서 다이어로그를 실행했을 때, 실행되기 전 액티비티는 다이어로그 뒤편에서는 여전히 보이기 때문에 Visible process에 해당한다.

 

* Visible(혹은 Foreground) 액티비티와 결속된 서비스는 Visible 프로세스에 속한다.

 

(3) Service process

 

startService() 메소드를 이용해서 시작된 서비스를 갖는 프로세스를 나타낸다. 비록 현재 실행되고 있는 서비스가 유저가 눈으로 확인할 수 있는 그 어떤 컴포넌트와 직접적인 관련성이 없으나, 해당 서비스와 관련된 내용을 사용자는 인지할 수 있다.
ex)백그라운드에서 음악 재생, 네트워크를 통해 데이터 다운로드)

 

(4) Background process

 

유저가 현재 보지 않는 화면(액티비티) 컴포넌트는 갖는 프로세스를 나타낸다. 해당 프로세스는 유저와 직접적인 관련성이 없기 때문에, 안드로이드 시스템이 다른 프로세스를 위한 메모리가 부족할 때, 시스템에 의해서 종료된다.

 

실행되는 Background 프로세스가 상당히 많이 존재하기 때문에, 해당 Background 프로세스는 LRU 리스트에 보관된다. 그렇기 떄문에, 가장 최근에 유저가 본 화면은 메모리에서 가장 나중에 제거된다.

 

(5) Empty process

 

어떤 컴포넌트도 갖고 있지 않는 프로세스를 나타낸다. 이 같은 프로세스를 유지하는 이유는 캐싱을 하기 위해서다. 캐싱을 함으로써 다음번에 프로세스를 좀 더 빠르게 실행할 수 있다.

시스템에서는 프로세스와 관련된 캐싱과 커널과 관련된 캐싱 사이에 균형을 맞추기 위해서 전반적인 시스템 자원의 균형을 맞춘다.

 

안드로이드는 특정 프로세스 내에서 사용되는 컴포넌트의 중요도를 기초로 해서 프로세스 중요도의 등급을 매긴다. 예를 들어, 프로세스가 서비스와 Visible 액티비티를 제공하고 있다면, 이 둘 중에 더 높은 중요도를 갖는 Visible 프로세스의 중요도를 갖게 된다.

 

프로세스 우선순위와 관련된 추가 내용

 

추가로, 프로세스의 등급은 해당 프로세스에 종속되는 다른 프로세스에 의해서 올라갈 수 있다. - 다른 프로세스에 서비스를 제공하는 프로세스는 자신의 서비스를 이용하는 프로세스 보다 우선순위가 낮아질 수 없다.

 

예를 들어, 프로세스 A에 존재하는 내용 제공자는 프로세스 B에 존재하는 클라이언트에 서비스를 제공할 수 있다, 혹은 프로세스 A에 존재하는 서비스는 프로세스B에 존재하는 컴포넌트와 결속(Binding)결속 될 수 있다. 이 때, 서비스를 제공하는 프로세스 A는 서비스를 이용하는 프로세스 B보다 항상 우선순위값이 높아야 한다.

 

서비스를 동작하는 프로세스는 Background 액티비티보다 더 높은 우선순위 값을 갖기 때문에, 오래 걸리는 작업을 처리할 때, 단순히 액티비티에서 작업 스레드를 생성해서 처리하기 보단 서비스를 생성해서 처리하는 것이 옳다.

 

예를 들어, 웹사이트에 사진을 업로드하는 액티비티는 그와 관련된 작업을 하는 서비스를 시작해야 한다.(서비스를 통해 작업 처리를 하면, 유저가 액티비티를 벗어나더라도 그와 상관없이 서비스는 백그라운드에서 계속 동작하기 때문이다.)

 

감사합니다 ^_^