
스마트폰을 사용하다 보면 "앱이 응답하지 않습니다"라는 메시지를 본 적이 있을 것이다. 또는 여러 앱을 실행하다가 갑자기 이전에 사용하던 앱이 처음부터 다시 시작되는 경험도 해보았을 것이다. 이러한 현상들은 모두 안드로이드의 프로세스 관리와 관련이 있다. 오늘은 안드로이드 프로세스가 무엇이고, 시스템이 이를 어떻게 관리하는지 알아보려고 한다.
안드로이드 프로세스는 애플리케이션이 실행되는 독립된 공간이다. 쉽게 말해, 각 앱이 자신만의 방을 가지고 있다고 생각하면 된다. 이 방 안에서 앱은 자유롭게 동작하지만, 다른 앱의 방에는 함부로 들어갈 수 없다. 이것이 바로 안드로이드의 샌드박스 보안 모델이다.
각 프로세스는 리눅스 시스템을 기반으로 하며, 고유한 사용자 ID와 프로세스 ID를 부여받는다. 이를 통해 앱들은 서로 격리되어 실행되며, 한 앱의 문제가 다른 앱이나 시스템 전체에 영향을 미치지 않도록 보호된다.
프로세스 안에는 가상머신(Dalvik 또는 ART), 메인 스레드, 그리고 앱의 모든 컴포넌트들이 포함된다. 기본적으로 하나의 앱은 하나의 프로세스에서 실행되지만, 필요에 따라 여러 프로세스를 사용할 수도 있다.
안드로이드는 제한된 메모리 자원을 효율적으로 관리하기 위해 프로세스를 우선순위별로 분류한다. 안드로이드 문서를 찾아보면 4단계로 분류하는 곳도 있고, 5단계로 분류하는 곳도 있다. 이는 안드로이드가 발전하면서 분류 체계가 진화했기 때문이다.
최신 안드로이드 공식 문서에서는 주로 4단계 분류를 사용한다. 이는 실제 시스템 동작을 더 정확히 반영하고, 개발자가 이해하기 쉽도록 단순화한 것이다.
1. Foreground Process (포그라운드 프로세스)
가장 높은 우선순위를 가지는 프로세스다. 현재 사용자가 직접 상호작용하고 있는 앱이 여기에 해당한다. 화면에 표시되어 터치 입력을 받고 있는 액티비티나, 음악 재생처럼 알림창에 표시되는 포그라운드 서비스가 이 단계에 속한다. 시스템은 이 프로세스를 거의 종료시키지 않으며, 정말 극단적인 메모리 부족 상황에서만 종료를 고려한다.
2. Visible Process (보이는 프로세스)
사용자에게 보이지만 직접적인 상호작용은 없는 프로세스다. 예를 들어, 다이얼로그가 위에 떠 있어서 부분적으로 가려진 액티비티가 이에 해당한다. 사용자가 인지하고 있는 상태이므로 시스템은 이 프로세스도 가능한 한 유지하려고 노력한다.
3. Service Process (서비스 프로세스)
백그라운드에서 서비스를 실행 중인 프로세스다. 파일 다운로드, 데이터 동기화 같은 작업이 여기에 속한다. 사용자가 직접 보지는 못하지만 사용자 경험에 영향을 미치므로 중요도가 높다. 다만 포그라운드나 보이는 프로세스를 위해 메모리가 필요하면 종료될 수 있다.
4. Cached Process (캐시된 프로세스)
더 이상 활성 컴포넌트가 없지만 메모리에 유지되는 프로세스다. 사용자가 다시 돌아왔을 때 빠르게 재시작하기 위한 캐시 역할을 한다. 시스템은 LRU(Least Recently Used) 방식으로 이들을 관리하며, 메모리가 필요하면 가장 오래된 것부터 종료시킨다.
안드로이드는 리눅스의 Out of Memory Killer를 개선한 Low Memory Killer를 사용한다. 이 시스템은 메모리 상황을 지속적으로 모니터링하면서, 설정된 임계값에 도달하면 우선순위가 낮은 프로세스부터 종료시킨다.
일반적인 데스크톱 운영체제와 달리, 안드로이드는 가능한 한 많은 프로세스를 메모리에 유지하려고 한다. 이는 앱 전환을 빠르게 하기 위함이다. 사용자가 최근 앱 목록에서 앱을 선택했을 때, 프로세스가 살아있다면 즉시 복원되지만, 종료되었다면 처음부터 다시 시작해야 한다.
때로는 하나의 앱이 여러 프로세스를 사용하는 것이 유리할 수 있다. 예를 들어, 음악 스트리밍 앱은 UI를 담당하는 메인 프로세스와 음악 재생을 담당하는 서비스 프로세스를 분리할 수 있다. 이렇게 하면 UI에 문제가 생겨도 음악 재생은 계속되고, 반대로 재생 서비스에 문제가 생겨도 UI는 정상 동작한다.
웹 브라우저도 좋은 예다. 각 탭을 별도의 프로세스로 실행하면, 한 탭이 멈추거나 충돌해도 다른 탭들은 영향을 받지 않는다. 크롬 브라우저가 이러한 아키텍처를 채택하고 있다.
하지만 프로세스 분리는 공짜가 아니다. 각 프로세스는 독립된 메모리 공간을 가지므로, 데이터를 공유하려면 특별한 메커니즘이 필요하다. 안드로이드는 이를 위해 Binder라는 IPC(Inter-Process Communication) 시스템을 제공한다.
프로세스 간 통신은 일반 메서드 호출보다 훨씬 복잡하고 느리다. 데이터를 직렬화하고, 전송하고, 다시 역직렬화하는 과정이 필요하기 때문이다. 따라서 정말 필요한 경우가 아니라면 단일 프로세스 구조를 유지하는 것이 좋다.
멀티태스킹을 하다가 이전 앱으로 돌아갔을 때 처음부터 다시 시작되는 경험이 있을 것이다. 이는 메모리 부족으로 해당 앱의 프로세스가 종료되었기 때문이다. 시스템은 프로세스를 종료하기 전에 액티비티의 상태를 저장하므로, 재시작 시 이전 상태를 어느 정도 복원할 수 있다. 하지만 모든 것이 완벽하게 복원되는 것은 아니므로, 개발자는 중요한 데이터를 적절히 저장하고 복원하는 로직을 구현해야 한다.
프로세스가 많이 실행될수록 배터리 소모가 늘어난다. 특히 백그라운드에서 계속 동작하는 서비스는 배터리의 주범이 될 수 있다. 이 때문에 안드로이드는 버전이 올라갈수록 백그라운드 프로세스에 대한 제한을 강화하고 있다.
안드로이드 8.0(오레오)부터는 백그라운드 서비스 실행에 큰 제약이 생겼고, 대신 JobScheduler나 WorkManager 같은 대안을 제공한다. 이들은 시스템이 최적의 시점에 작업을 실행하도록 하여 배터리를 절약한다.
메모리 누수는 프로세스가 불필요하게 커지게 만들어 시스템에 부담을 준다. 특히 안드로이드에서는 액티비티 참조를 잘못 관리하면 쉽게 메모리 누수가 발생한다. 액티비티는 전체 UI 계층과 연결되어 있어 하나만 누수되어도 큰 메모리를 낭비하게 된다.
프로세스가 언제든 종료될 수 있다는 것을 항상 염두에 두어야 한다. 사용자가 입력한 데이터, 스크롤 위치, 선택 상태 등 중요한 정보는 적절한 시점에 저장해야 한다. 동시에 너무 자주 저장하면 성능에 영향을 미치므로 균형을 찾는 것이 중요하다.
모든 작업을 포그라운드에서 처리할 수는 없지만, 백그라운드 작업도 신중하게 설계해야 한다. 꼭 필요한 작업인지, 즉시 실행해야 하는지, 특정 조건(WiFi 연결, 충전 중)에서만 실행해도 되는지를 고려해야 한다.
안드로이드의 프로세스 관리는 제한된 모바일 환경에서 최적의 성능과 사용자 경험을 제공하기 위한 정교한 시스템이다. 분류 체계가 시간에 따라 진화했지만, 그 목적은 변하지 않았다. 바로 제한된 자원을 효율적으로 관리하면서도 사용자에게 매끄러운 경험을 제공하는 것이다.
프로세스는 단순히 기술적인 개념이 아니라, 사용자 경험과 직결되는 중요한 요소다. 앱이 빠르게 실행되고, 안정적으로 동작하며, 배터리를 적게 소모하는 것 모두가 올바른 프로세스 관리에서 시작된다. 안드로이드 시스템과 조화롭게 동작하는 앱을 만들어, 사용자에게 더 나은 경험을 제공하는 것이 우리 개발자의 역할이다.