안드로이드 운영체제 관련 정리

pnlkc·2023년 3월 2일
1
post-thumbnail

목차

  1. 운영체제란?

  2. 안드로이드 운영체제의 구조

  3. 안드로이드에서 네이티브 코드란?

  4. 프로세스와 스레드

  5. 프로세스 우선순위


운영체제란?


운영체제Operating System으로 일반적으로 OS라 말합니다.

운영체제는 컴퓨터 시스템의 기본적인 구성요소이며, 하드웨어와 소프트웨어 응용 프로그램을 연결하고 관리하는 시스템 소프트웨어라고 할 수 있습니다.

커널(Kernel)은 운영체제의 핵심이 되는 부분으로 하드웨어와 프로그램 사이에 인터페이스를 제공하고, 하드웨어와 소프트웨어의 리소스를 관리합니다. 즉, 운영체제는 커널을 통해 시스템 전반을 통제합니다.


운영체제의 대표적인 기능들은 다음과 같습니다.


1. 리소스 관리

  • 컴퓨터의 CPU, 메모리(RAM), 보조 기억장치 및 네트워크와 같은 하드웨어 리소스를 관리합니다
  • 운영체제, 프로그램, 드라이버와 같은 소프트웨어 리소스도 관리합니다.

2. 장치 드라이버

  • 키보드, 마우스, 모니터와 같은 하드웨어 장치를 제어하기 위한 장치 드라이버를 제공합니다.

3. 사용자 인터페이스

  • 사용자가 컴퓨터와 상호작용할 수 있는 UI(User Interface, 사용자 인터페이스)를 제공합니다.

4. 보안

  • 사용자 및 프로그램의 보안을 관리하고, 사용자 인증 및 권한 관리 등의 기능을 제공합니다.

5. 프로그램 실행

  • 프로그램을 실행하고, 프로그램이 컴퓨터의 하드웨어 및 소프트웨어 리소스에 액세스 할 수 있도록 합니다.



안드로이드 운영체제의 구조


안드로이드 운영체제는 리눅스(Linux) 커널과 이에 기반한 안드로이드 소프트웨어 스택으로 구성되어 있습니다.


안드로이드 운영체제에서 리눅스 커널이 가지는 특징은 다음과 같습니다.


  • 안드로이드 운영체제의 핵심인 리눅스 커널은 안드로이드 운영체제에서 하드웨어를 제어하고 안드로이드 애플리케이션과 다른 시스템 서비스가 상호작용할 수 있도록 인터페이스를 제공합니다.

  • 리눅스 커널은 멀티태스킹, 메모리 관리, 네트워킹 등 안드로이드에서 필요한 다양한 기능을 제공합니다.

  • 안드로이드 운영체제에서 리눅스 커널은 모바일 기기의 하드웨어 리소스를 관리하고 이를 통해 안드로이드 애플리케이션은 카메라, 스피커, 마이크, 디스플레이 등의 하드웨어를 이용하여 사용자에게 다양한 기능을 제공할 수 있습니다.

  • 리눅스 커널은 안드로이드 운영체제에서 보안을 담당합니다.


안드로이드 소프트웨어 스택은 다음과 같이 4개의 주요 계층으로 구성됩니다.


1. 응용 프로그램 계층 (Application Layer)

  • 안드로이드 운영체제의 가장 상위 계층으로, 사용자와 직접 상호작용하는 애플리케이션들을 포함합니다.

  • 안드로이드 사용자 경험의 핵심을 이루며, 다양한 종류의 애플리케이션들이 모두 이 계층에서 실행됩니다.

  • 사용자 인터페이스, 애플리케이션 로직, 데이터 관리 및 다양한 기능을 수행하는 애플리케이션들로 구성됩니다.

2. 애플리케이션 프레임워크 계층 (Application Framework Layer)

  • 안드로이드 운영체제에서 제공하는 애플리케이션 개발을 위한 API(Application Programming Interface)를 제공하는 계층입니다.

  • 안드로이드 응용 프로그램 계층과 안드로이드 런타임 계층 사이에 위치하며, 안드로이드 애플리케이션 개발자들이 안드로이드 운영체제에서 제공하는 다양한 기능들을 활용할 수 있도록 도와줍니다.

  • 안드로이드의 컴포넌트들(액티비티, 서비스, 브로드캐스트 리시버, 콘텐츠 프로바이더 등), 데이터베이스 연동, 메시지 전송, 위치 정보, 각종 센서 등을 다룰 수 있는 API를 제공합니다.

  • 안드로이드 리소스 관리 및 액티비티 관리와 같은 중요한 기능들을 포함합니다.

3-1. 안드로이드 런타임 계층 (Android Runtime Layer)

  • 안드로이드 애플리케이션을 실행하는 데 필요한 기능(컴파일)을 제공하는 계층입니다.

  • 안드로이드에서는 자바 가상 머신(JVM) 기반의 런타임 환경인 Dalvik을 사용하다 최근에는 ART(안드로이드 런타임)을 사용하고 있습니다.

  • ART는 JIT(Just-In-Time) 컴파일러가 아닌 AOT(Ahead-Of-Time) 컴파일러를 사용하기 때문에 Dalvik보다 성능이 뛰어나지만, 더 많은 메모리를 사용합니다.

  • 이 계층은 네이티브 코드(C/C++)를 실행할 수 있는 인터페이스를 제공합니다

3-2. 네이티브 라이브러리 계층 (Native Library Layer)

  • 안드로이드 애플리케이션이 실행될 때 사용되는 C/C++ 라이브러리들을 포함하는 계층입니다.

  • 네이티브 라이브러리의 안드로이드 시스템 라이브러리를 통해 안드로이드 운영체제에서 다양한 시스템 레벨의 기능들(그래픽 처리, 오디오 및 비디오 인코딩/디코딩, 네트워크 연결, 데이터베이스 액세스 등)을 수행하는데 사용됩니다.

  • 이 계층을 통해 안드로이드 NDK(Native Development Kit)를 사용하여 C/C++ 코드를 작성하고, 이를 안드로이드 애플리케이션에 포함시켜 사용할 수 있습니다.

4. 하드웨어 추상화 계층 (Hardware Abstraction Layer)

  • 안드로이드 운영체제는 다양한 하드웨어(카메라, GPS, 조도 센서, wifi 모듈 등)와 함께 동작하는데, 이 계층에서는 각각의 하드웨어를 추상화하여 애플리케이션 프레임워크 계층에 제공합니다.

  • 하드웨의 추상화된 인터페이스를 이용하기 때문에 안드로이드 애플리케이션 개발자들은 하드웨어와 관련된 복잡한 작업을 수행하지 않아도 됩니다.

  • 하드웨어 추상화 계층은 리눅스 커널과 하드웨어 (드라이버) 사이에서 작동합니다.


정리하면,
안드로이드 운영체제는 리눅스 커널4개의 안드로이드 소프트웨어 스택으로 구성되어 있으며,
리눅스 커널은 안드로이드 운영체제의 핵심적인 관리자 역할을 하고,
각각의 계층에서는 필요한 기능들을 제공하여 안드로이드 애플리케이션 개발에 필요한 환경을 제공합니다.




안드로이드에서 네이티브 코드란?


안드로이드에서 네이티브 코드(Native code)란, C, C++ 등의 프로그래밍 언어로 작성된 코드를 의미합니다.

  • 네이티브 코드는 안드로이드 운영체제에서 직접 실행되기 때문에 Java나 Kotlin과 같은 안드로이드 프로그래밍 언어보다 더 높은 성능을 제공합니다.

  • 안드로이드에서 네이티브 코드를 사용하려면, 안드로이드 NDK(Native Development Kit)를 사용해야 합니다. NDK는 C, C++ 등의 네이티브 언어로 개발된 코드를 컴파일하고, 안드로이드 운영체제에서 실행 가능한 형태로 변환해 주는 도구입니다.

  • NDK를 사용하려면 JNI(Java Native Interface)를 사용하여 네이티브 코드와 자바 코드를 연결해야 합니다. JNI를 사용하면 자바 코드에서 네이티브 함수를 호출하거나, 네이티브 코드에서 자바 객체를 생성하거나, 자바 콜백 함수를 호출할 수 있습니다.


네이티브 코드를 사용하는 것은 더 높은 성능을 제공하지만 주의해야 할 점이 있습니다.

  • 네이티브 코드는 안드로이드 운영체제와 밀접하게 연관되어 있기 때문에, 안드로이드 OS와 네이티브 코드 간의 호환성 문제가 발생할 수 있습니다.

  • 네이티브 코드는 일반적으로 자바나 코틀린보다 낮은 수준의 언어로 작성되기 때문에, 보안 문제와 메모리 누수 등의 문제가 발생할 수 있습니다.

때문에 안드로이드에서 네이티브 코드를 사용할 때는 안드로이드 운영체제와의 호환성을 고려해야 하고, 보안 및 메모리 관리를 엄격하게 처리해야 합니다.




프로세스와 스레드


프로세스스레드는 모두 컴퓨터 시스템에서 실행 단위를 나타냅니다.

실행 단위는 프로그램 코드를 실행할 수 있는 최소한의 단위를 의미합니다.


프로세스(Process)


프로세스는 실행 중인 프로그램의 인스턴스이고 하나 이상의 스레드를 통해 실행됩니다.

여기까지만 보면 잘 이해가 되지 않지만, 프로세스가 스레드보다 범위가 더 큰 것 같다는 느낌이 있습니다.

프로그램의 인스턴스라는 것은 어떤 프로그램(ex. 메모장, 계산기 등)이 메모리(RAM)의 영역과 CPU 시간등 자원을 할당 받아 실행되고 있는 상태를 의미합니다.

프로세스는 운영체제로부터 자원을 할당받는데, 이렇게 할당 받은 자원을 가지고 독립적으로 실행 됩니다.

프로세스는 메모리 공간, 파일 핸들, 네트워크 연결 등의 자원을 독립적으로 사용하기 때문에 일반적으로 한 프로세스는 다른 프로세스에 접근할 수 없습니다.

프로세스가 다른 프로세스와 통신을 하기 위해서는 IPC(Inter-Process Communication) 메커니즘을 사용해야 합니다. IPC는 다른 프로세스와 데이터를 주고받기 위한 방법으로, 안드로이드에서는 Binder, Intent, Content Provider 등의 IPC 메커니즘이 주로 사용됩니다.


스레드에 대해 알아보기 전에 프로세스의 메모리 영역이 어떤 구조로 이루어져 있는지 알아야 합니다.

프로세스의 메모리 영역은 다음과 같은 구조를 가집니다.

  1. Code : 프로세스가 실행할 코드를 저장하는 메모리 영역입니다. 이 영역은 읽기 전용으로, 실행 중에 수정이 불가능합니다.
  2. Data : 전역(Global) 변수와 정적(Static) 변수가 저장되는 메모리 영역입니다. 이 영역은 실행 중에 수정이 가능합니다.
  3. Heap : 동적으로 할당되는 메모리 영역입니다. 메모리를 동적으로 할당하여 사용하는 경우, 이 영역에서 할당됩니다.
  4. Stack : 함수 호출과 관련된 지역 변수, 매개 변수, 함수 호출 시 저장되는 반환 주소 등이 저장되는 메모리 영역입니다. 스택은 후입선출(LIFO) 구조로 동작하며, 함수 호출과 관련된 정보가 스택에 쌓이고, 함수가 반환되면 해당 정보가 스택에서 제거됩니다.


스레드(Thread)


스레드프로세스 내부에서 실행되는 실행 단위입니다.

스레드부모 프로세스 내의 메모리 공간을 차지하고, 부모 프로세스로부터 자원을 공유 받아 사용합니다.

하지만 모든 영역의 자원을 공유하는 것은 아니고, 스레드는 프로세스의 메모리 영역 중 Code, Data, Heap 영역은 공유합니다. 하지만 Stack 영역은 고유하게 가지게 됩니다.

스레드는 프로세스로부터 자원을 공유 받기 때문에 하나의 프로세스에서 여러 개의 스레드가 동시에 실행 되는 경우 자원 경합(충돌)이 발생할 수 있습니다.

이러한 자원 경합을 방지하기 위해 스레드는 프로세스 내에서 공유한 자원에 대해 동기화 과정이 필요합니다.


멀티 프로세스 vs 멀티 스레드


멀티 프로세스, 멀티 스레드 모두 하나의 프로그램에 대한 작업을 동시에 하기 위한 처리 방식을 의미합니다.

프로세스와 스레드가 다르다면 멀티 프로세스와 멀티 스레드도 다를 것이라는 것을 알 수 있습니다.

멀티 프로세스와 멀티 스레드를 비교하기 전에, 컨택스트(Context)와 컨택스트 스위칭(Context Switching)이라는 용어에 대해 알아야 합니다.

컨택스트는 CPU 레지스터나 메모리 상태 등 프로세스나 스레드가 실행될 때 필요한 모든 정보(메타데이터)를 말합니다.

컨택스트는 PCB(Process Control Block)에 저장되고 관리됩니다. PCB는 프로세스의 중요한 정보를 포함하고 있기 때문에 커널 스택의 가장 앞부분에서 관리되어 일반 사용자가 접근할 수 없습니다.

컨택스트 스위칭은 CPU가 여러 개의 프로세스나 스레드를 번갈아 가면서 실행할 때, 현재 실행 중인 프로세스나 스레드의 컨택스트를 저장하고, 다음에 실행할 프로세스나 스레드의 컨택스트를 불러오는 작업을 의미합니다.

멀티 프로세스는 하나의 프로그램을 여러 개의 독립된 프로세스로 나누어 실행되도록 하는 방식입니다.

  • 멀티 프로세스의 장점
  1. 각각의 독립된 프로세스에서 나누어 실행 되기 때문에 하나의 프로세스가 죽는 등의 오류가 발생해도 다른 프로세스는 영향을 받지 않아 안정성이 높습니다.

  2. 각각의 독립된 프로세스에서 나누어 실행 되기 때문에 자원을 공유하지 않아 별도의 동기화 작업이 필요하지 않습니다.

  • 멀티 프로세스의 단점
  1. 프로세스 사이에 통신을 하기 위해서는 IPC를 사용해야 하기 때문에 프로세스 사이에 통신을 할 때 비용이 많이 듭니다.

  2. 컨택스트 스위칭 비용이 많이 듭니다.

  3. 각 프로세스가 독립적인 자원을 가지기 때문에 메모리에서 차지하는 공간이 큽니다.


멀티 스레드는 하나의 프로그램을 하나의 프로세스 안에서 여러 개의 스레드를 사용하여 실행하는 것을 의미합니다.

  • 멀티 스레드의 장점
  1. 각 스레드는 자원을 공유하는 등 서로 긴밀하게 연결되어 있기 때문에 스레드 사이에 통신을 할 때 비용이 적게 듭니다.

  2. 컨택스트 스위칭 비용이 적게 듭니다.

  3. 하나의 프로세스 안에서 자원을 공유하기 때문에 메모리에서 차지하는 공간이 적습니다.

  • 멀티 스레드의 단점
  1. 멀티 스레드에서는 스레드 사이의 자원 경합이 발생할 수 있기 때문에 안전성을 보장하기 위해서는 스레드 동기화 작업을 추가적으로 해야 합니다.

  2. 하나의 스레드에서 발생한 오류가 다른 스레드에도 영향을 미칠 수 있습니다.



안드로이드에서 프로세스와 스레드


안드로이드 앱은 일반적으로 하나의 프로세스에서 실행되며, 각각의 액티비티, 서비스, 브로드캐스트 리시버, 콘텐트 프로바이더 등의 컴포넌트는 단일 스레드 모델에 따라 하나의 단일 스레드에서 실행 됩니다.

안드로이드에서 단일 스레드 모델을 사용하는 이유는 앱의 생명 주기를 관리하기 용이하고, UI 업데이트 및 이벤트 처리를 단순하게 만들어 주는 등이 있습니다. 또한 불필요하게 멀티 스레드 방식을 사용하는 경우 CPU와 메모리 자원을 과도하게 사용하여 기기의 성능에 부정적인 영향을 줄 수도 있습니다.

하지만 필요한 경우 메니페스트 파일에서 컴포넌트가 실행되는 프로세스를 별도로 지정할 수 있고, 여러 스레드를 사용하여 앱을 실행할 수도 있습니다.

안드로이드에서 멀티 프로세스의 개념도 중요하지만 더 중요하게 봐야하는 부분은 멀티 스레드입니다.

안드로이드 앱은 일반적으로 단일 스레드에서 실행되는데 이 단일 스레드를 메인 스레드 혹은 UI 스레드라고 합니다.

안드로이드 앱이 단일 스레드 실행되는 과정에서 네트워크 작업, 데이터베이스 작업, 파일 입출력 등 자원을 많이 소모하는 작업을 하는 경우에 UI 스레드가 작업이 완료될 때까지 멈춰 있게 됩니다.

이 경우 약 5초 이상동안 UI 스레드가 멈춰 있게 되면 ANR(Application Not Responding) 오류가 발생하게 됩니다.

이러한 문제를 해결하기 위해 무거운 작업을 UI 스레드에서 분리하여 별도의 스레드가 처리하게 하는 방식의 멀티 스레드 방식을 사용해야 합니다.

안드로이드에서 멀티 스레드 방식을 사용할 때 지켜야하는 규칙은 다음과 같습니다.

  • UI 업데이트는 메인 스레드(UI 스레드)에서만 처리해야 합니다.

    안드로이드에서 UI 업데이트는 메인 스레드에서만 처리해야 합니다. 그렇지 않으면 앱이 느려지거나 멈추는 문제가 발생할 수 있습니다. 따라서 백그라운드 스레드에서 작업한 후 그 결과를 가지고 메인 스레드에서 UI를 업데이트 해야 합니다.

  • 백그라운드 작업은 별도의 스레드에서 처리해야 합니다.

    메인 스레드에서는 오랜 시간이 걸리는 작업을 처리하지 않아야 합니다. 대신에, Coroutine, RxJava와 같은 라이브러리나 AsyncTask, Handler, ThreadPoolExecutor 등과 같은 클래스를 통하여 백그라운드 스레드에서 작업을 처리해야 합니다. 특히 안드로이드 앱에서 네트워크 작업 등의 I/O 작업은 반드시 비동기식으로 처리해야 합니다.

  • 메모리 누수에 대해 고려해야 합니다.

    멀티 스레드는 단일 스레드보다 더 많은 메모리를 사용하므로 작업이 완료된 후 AsyncTask 같은 객체의 참조를 해제하여 메모리 누수를 방지해야 합니다.

  • 공유 자원에 대한 접근에 주의해야 합니다.

    여러 개의 스레드가 동시에 공유 자원에 접근할 때, 안전성을 높이기 위해서는 synchronized 또는 Lock 등을 통한 추가적인 작업이 필요합니다.


프로세스 우선순위


프로세스 우선순위란 프로세스가 시스템 자원을 어떤 우선순위를 가지고 사용할지 결정하는 방법을 의미합니다.

중요도가 낮은 프로세스부터 종료시키면서 시스템 자원을 관리합니다.


안드로이드 개발자는 안드로이드 프로세스 우선순위를 알아야 하는 이유는 아래와 같습니다.

  • 안드로이드는 메모리가 부족할 때 중요도가 낮은 프로세스를 제거하기 때문에, 개발자는 어떤 상황에서 자신의 앱이 종료될 수 있는지 알고 대비해야 합니다.

  • 안드로이드는 프로세스 우선순위에 따라 CPU 자원(시간)을 배분하는 CPU 스케줄링하기 때문에, 개발자는 자신의 앱이 필요한 성능과 배터리 소모 등을 파악하고 최적화해야 합니다.

  • 안드로이드는 프로세스 우선순위에 따라 메모리, 네트워크, 파일 등을 할당하기 때문에, 개발자는 자신의 앱이 필요한 자원을 적절하게 요청하고 해제해야 합니다.


안드로이드의 프로세스 우선순위


안드로이드의 프로세스 우선순위는 5가지로 분류됩니다.

중요도가 높은 순서대로 설명하면 아래와 같습니다.

1. 활성 프로세스(Foreground Process)

  • 현재 사용자와 직접 상호작용하는 액티비티나 서비스를 가진 프로세스입니다.

2. 화면에 보이는 프로세스(Visible Process)

  • 현재 화면에 보이지만 사용자와 상호작용하지는 않는 액티비티나 서비스를 가진 프로세스입니다.

3. 시작된 서비스 프로세스(Started Service Process)

  • 화면에 직접적으로 표시되지는 않지만 계속 실행되는 서비스를 가진 프로세스입니다.

4. 백그라운드 프로세스(Background Process)

  • 화면에 보이지 않는 액티비티나 실행중이지 않는 서비스를 가진 프로세스입니다.

5. 빈 프로세스(Empty Process)

  • 앱의 수명주기가 종료되고 메모리에 캐시되어 남아있는 프로세스입니다.
profile
안드로이드 개발 공부 블로그

0개의 댓글