[Android] 프로세스(process) 및 스레드(thread)

참고링크 : https://developer.android.com/guide/components/processes-and-threads?hl=ko

애플리케이션 구성 요소가 시작되고, 앱에 실행 중인 다른 구성 요소가 없으면 하나의 실행 스레드로 앱의 Linux 프로세스 시작함. 기본적으로 같은 애플리케이션의 모든 구성 요소는 같은 프로세스와 스레드에서 실행됨. 하지만 여러가지 구성 요소가 각자 별도의 프로세스에서 실행되도록 할 수도 있고, 어느 프로세스에든 추가 스레드를 만들 수 있음.


프로세스

기본적으로 같은 앱의 모든 구성 요소는 같은 프로세스와 스레드에서 실행되고 이를 바꾸면 안됨. 그러나 어느 프로세스가 특정 구성 요소에 속하는지 확인해야 할 경우 매니페스트 파일에서 확인 가능.(android:process 속성)

  • 지원하는 요소 : <application>, <activity>, <service>, <receiver>, <provider>

안드로이드 시스템에서 어느 프로세스를 삭제할지 결정할 때, 이들의 상대적 중요성을 가늠함.


프로세스 수명 주기

안드로이드 시스템은 프로세스에서 실행되는 구성 요소와 해당 구성 요소의 상태에 기초하여 각 프로세스에 "중요 계층"을 부여함. 중요도가 낮은 프로세스가 먼저 제거됨.


  • 중요 계층 5가지
    1. 포그라운드 프로세스 : 사용자가 현재 진행하는 작업에 필요한 프로세스 (Activity나 Foreground Service)
      • 사용자가 상호작용하는 Activity를 호스팅할 경우
      • 사용자와 상호작용하는 액티비티에 바인드된 Service를 호스팅할 경우
      • 포그라운드에서 실행되는 Service를 호스팅할 경우
      • 수명 주기 콜백 중 하나를 실행하는 Service를 호스팅할 경우 (onCreate(), onStart() 또는 onDestroy() )
    2. 가시적 프로세스 : 포그라운드 구성 요소는 없지만 사용자가 화면에서 보는 것에 영향을 미칠 수 있는 프로세스
      • 맨 앞에 있지는 않지만 사용자에게 보이는 Activity 를 호스팅할 경우
      • 눈에 보이는 액티비티에 바인딩된 Service 호스팅할 경우
    3. 서비스 프로세스 : startService() 메서드로 시작되었지만, 위 경우에 들어가지 않는 서비스를 실행 중인 프로세스일 경우
    4. 백그라운드 프로세스 : 현재 사용자에게 보이지 않는 액티비티를 보유한 프로세스. 이러한 프로세스는 LRU(최저 사용 빈도) 목록에 보관하여 사용자가 가장 최근에 본 액티비티가 있는 프로세스가 가장 마지막에 중단되도록 함.
    5. 빈 프로스세스 : 활성 앱 구성 요소를 보유하지 않은 프로세스.

프로세스의 등급은 다른 프로세스가 이에 의존할 경우 상승 가능.(의존 대상의 중요도가 의존할 대상과 같거나 높음)


스레드

앱이 시작되면 앱에 대한 실행의 스레드를 생성하며, 메인 스레드라 함. 이 스레드는 드로어블 이벤트를 포함한 UI 위젯에 이벤트를 발송하는 역할을 맡기도 하여 UI 스레드라고도 함.


시스템은 구성 요소의 각 인스턴스에 대해 별도의 스레드를 생성하지 않음. 같은 프로세스에서 실행되는 모든 구성 요소는 UI 스레드에서 시작되고, 구성 요소를 호출하는 시스템이 해당 스레드에서 발송됨.


시스템 콜백에 응답하는 메서드(onKeyDown()이나 생명주기 메서드 등)는 항상 프로세스의 UI 스레드에서 실행됨.


UI 스레드에서 DB 쿼리 등의 긴 작업을 수행하면 사용자가 보기에 앱이 중단된 것처럼 보이며, 약 5초이상 진행되면 ANR 대화상자가 표시됨.


안드로이드 UI 도구 킷은 스레드로부터 안전하지 않아 worker 스레드에서 처리하면 안됨.


Worker 스레드

단일 스레드 모델로 인해 앱 UI의 반응성을 위해서는 UI 스레드를 차단하지 않는 것이 중요함. 이를 위해 시간이 걸리는 작업들은 별도의 스레드에서 수행하며 이를 백그라운드 또는 워커 스레드라 함.


  • 안드로이드가 다른 스레드에서 UI 스레드에 액세스하기 위해 제공하는 방식
    • Activity.runOnUiThread(Runnable)
    • View.post(Runnable)
    • View.postDelayed(Runnable, long)

작업이 복잡해질수록 위 방식은 더 복잡해지므로, 더 복잡한 인터렉션을 처리하려면 worker 스레드에서 Handler를 사용하여 UI 스레드에 전달받은 메시지를 처리하는 방안을 고려해야 함. 최선의 해결책은 AsyncTask 클래스를 확장하여 사용하는 것.


AsyncTask

AsyncTask를 사용하면 UI에서 비동기식 작업을 수행할 수 있게 해줌. woker 스레드에서 작업을 수행하고 그 결과를 UI 스레드에 게시하므로 직접 스레드 및 핸들러를 처리할 필요가 없음.


AsyncTask를 서브 클래스로 지정한 다음, 백그라운드 스레드 풀에서 실행되는 doInBackground() 콜백 메서드를 구현하고, UI 업데이트를 위해 onPostExecute() 를 구현해야 함.


  • 매개 변수의 유형, 진행률 값과 최종 값을 제네릭을 사용하여 지정할 수 있음
  • doInBackground()는 worker 스레드에서 실행됨.
  • onPreExecute(), onPostExecute() 및 onProgressUpdate()는 UI 스레드에서 호출됨.
  • doInBackground()가 반환한 값이 onPostExecute() 로 전달됨.
  • publishProgress()를 doInBackground()에서 호출하여 UI 스레드에서 onProgressUpdate()를 실행함.
  • 모든 스레드에서 언제든 작업을 취소할 수 있음.

Thread-safe 메서드

어떤 경우에는 구현하는 메서드가 하나 이상의 스레드에서 호출되는 일이 있어 안전하게 작성해야 함.


주로 원격으로 호출할 수 있는 메서드이 있음. 바인드된 서비스 등.


IBinder에서 구현된 메서드가 IBinder가 실행되는 프로세스에서 호출될 경우, 해당 메서드는 호출자의 스레드에서 실행됨. 호출이 다른 프로세스에서 발생하면, 해당 메서드는 시스템이 IBinder 와 같은 프로세스에 유지하는 스레드 풀에서 선택된 스레드에서 실행됨.(프로세스의 UI 스레드에서 실행되지 않음)


위와 같은 이유로 스레드로부터 안전한 구현이 필요함.


프로세스 간 통신

안드로이드는 원격 프로시저 호출(RPC)을 사용한 프로세스 간 통신(IPC) 매커니즘을 제공함.


여기서 메서드는 액티비티나 다른 앱 구성 요소에 호출되지만 원격으로 실행되고, 결과는 모두 호출자에게 되돌려 보냄.


메서드 호출과 데이터는 운영 체제가 이해할 수 있는 수준으로 분해되고, 로컬 프로세스와 주소 공간에서 원격 프로세스와 주소 공간으로 전송되어 다시 결합되어 호출에 응답하게 됨. 그런 다음 반환 값이 반대 방향으로 전송됨.


안드로이드가 이와 같은 IPC 트랜잭션을 수행하는데 필요한 코드를 제공하므로, 개발자는 RPC 프로그래밍 인터페이스를 정의하고 구현하는 데만 집중하면 됨.


IPC 수행시 bindService()를 사용하여 앱이 서비스에 바인드 되어야 함.

+ Recent posts