반응형

ㅎㅇ헬로

유저영역이랑 커널영역에 대하여 아십니까?

그게 뭔데 씹덕아? 라는 나쁜말은 하지 말아주세요.

바로 오늘의 주제는 유저영역과 커널영역에 대하여 알아보기 입니다 ㅋㅅㅋ

사실 커널의 개념만 알면 쉬운  주제입니다. 커널의 약간 확장 개념이라고 보시면 될 것 같습니다.

반대로 커널에 대해 모르면 이해하기 힘들 수도 있습니다!

바로 ㄱㄱ싱 하시죠.


유저영역과 커널영역

유저영역과 커널영역은 운영체제에서 정말로 중요한 개념이랍니다?

대체 뭐길래 그러는걸까요...

바로 시스템 자원(메모리, 프로세서, 장치 등)의 접근 권한을 설정하기 위해 나눈 개념입니다.

각 영역은 무슨 역할을 하고, 왜 나눈 것일까요?


●커널영역

커널영역은 프로세스의 주소공간을 제외한 나머지 영역을 칭합니다.

커널영역에는 커널이 위치하고 있습니다. 때문에 모든 시스템 자원에 대한 권한이 있습니다.

여기서 권한에 대한 예시를 들자면, 파일을 읽어오거나, 쓰는 작업, 혹은 저장하는 등의 하드웨어적인 부분에 대한 접근 권한이라 할 수 있겠습니다.

시스템 자원에 대한 처리 및 메모리 할당과 해제를 해주고, 외에 CPU스케줄링 등을 해주는 영역입니다.

 

시스템 자원에 대하여 직접적으로 접근할 수 있어 속도가 빠릅니다.

 

●유저영역

유저영역은 프로세스의 주소공간인 스택, 힙, 코드, 데이터 영역을 칭합니다.

유저영역은 시스템 자원에 직접적으로 접근할 수 없습니다.

일반적으로 소프트웨어 개발자가 애플리케이션 로직, 사용자 인터페이스, 데이터 처리 및 관련 기능을 구현하는 영역입니다.

시스템 자원에 대한 접근을 하려면 시스템 호출을 통해 접근해야 하기 때문에 속도가 느립니다.


유저영역과 커널영역간의 전환, System Call

앞서 유저영역과 커널영역에 대해 간략히 말씀을 드렸는데요? 한 가지 궁금증이 생겨버립니다.

우리가 개발하는 환경은 유저영역인데, 유저영역은 시스템 자원에 접근할 수 없습니다. 그럼 시스템 자원은 못쓰는 것일까요? 사실 그럴리가 없죠. 위에서 이미 설명도 했답니다? 

유저영역에서 시스템 자원에 접근하려면 커널영역에 요청을 해야합니다. 이 때 커널영역에 접근을 해야하는데, 이 과정을 시스템 호출(System Call)이라고 합니다.

시스템 호출은 매우 중요한 개념입니다. 성능과 관련이 매우 밀접하기 때문이죠. 왜 성능과 관련이 있을까요?

시스템 호출(System Call)은 유저영역에서 커널영역으로 전환하는 과정을 거칩니다. 이 때 운영체제는 장치문맥을 교환(Context Switching)하게 되는데요, 이 비용이 상당합니다.

 

+++ 추가로 커널객체에 대하여 간단하게

특정 시스템 자원에 접근할 수 있는 객체를 커널객체라 하는데, 이 객체를 유저영역에서 직접 쓸 순 없고, Handle이라는 개체로 유저영역에 넘겨주게 됩니다. 유저영역에선 Handle을 통해 커널에게 해당 객체의 특정요청을 보낼 수 있습니다.

(당연하게도 커널객체는 커널영역에 할당되는 것이고, Handle은 유저영역에 할당되는 메모리입니다.)


 유저영역과 커널영역을 왜 나눴을까

유저모드와 커널모드는 분리됨으로써 여러 장점을 취할 수 있습니다.

 

안정성 : 서로의 영역이 분리됨으로써 어플리케이션에서 심각한 오류가 발생되어도 통상적으로 커널엔 심각한 영향을 끼치지 않는 경우가 많습니다.

 

보안 : 프로그램이 시스템 자원에 접근할 때 커널을 통해 요청하도록 함으로써, 권한 검사를 수행할 수 있습니다. 이를 통해 악의적인 코드가 시스템 자원을 부적절하게 사용하지 못하게 합니다. (객체지향프로그래밍을 해보신 분이라면 쉽게 이해할 수 있을텐데요, class의 private멤버를 public함수를 통해 특정 접근권한만 주는거랑 비슷하다고 볼 수 있습니다.)

 

효율성 : 커널은 시스템 자원에 대한 최적화된 접근 방식을 제공하고, 내부적으로 CPU와 메모리 자원을 효율적으로 관리합니다. (하지만 자주 상호작용할 경우 System Call로 인해 오버헤드가 발생할 수 있습니다.)


 

이번에 유저영역과 커널영역에 대해 다뤄봤습니다만, 컴퓨터 구조라는 것은 눈에 보이지 않기 때문에 추상적으로 느껴질 수 밖에 없다고 생각합니다. 그래서 예시를 한가지 들어보려고 합니다.

 

저는 개인적으로 유저영역과 커널영역을 개인과 은행의 대출관계와 비슷하다고 생각합니다.

 

  • 개인 : 유저영역
  • 은행 : 커널영역
  • 현금 : 중요 시스템 자원, 즉 커널 객체
  • 통장 : 시스템 자원을 쓰기 위한 수단, 즉 Handle

 

현금은 우리의 생활에서 상당히 중요한 자원입니다.

우리는 현금이 필요할 때, 은행에게서 현금 대출을 요청(System Call) 하는데요.

이때 은행은 대출조건을 검사하고 적합할 경우 통장을 통해 현금을 빌려주게 됩니다.

 

이 과정을 간략히 나타내면,

 

1. 현금을 은행에게 요청 (커널 객체를 커널 영역에서 요청)

2. 은행은 요청을 받고 검사하는데 시간이 걸림 (유저영역 -> 커널영역간의 전환 비용)

3. 검사 결과가 적합할 시 은행은 통장을 통해 현금을 줌 (커널 객체를 Handle 로 반환해줌)

4. 개인은 빌린 대출을 갚아야함 (커널 객체를 Handle을 통해 메모리 해제)

 

이렇게 나타낼 수 있습니다.

단, 저는 이해를 돕기 위해 예시를 든 것 뿐이지, 완벽한 예시란건 없다고 생각합니다. 알아서 걸러들으시길 ㅇㅅㅇ

 

또한 유저영역과 커널영역에 대한 상식을 만화로 잘 표현하신 분이 있습니다. 이 게시글을 보는 것도 도움이 될 것 같습니다.

유저영역과 커널영역 혹은 유저모드와 커널모드 : 네이버 블로그 (naver.com)

 

유저영역과 커널영역 혹은 유저모드와 커널모드

운영체제가 하는 일은 여러가지가 있지만, 컴퓨터의 메모리를 관리하는 일은 운영체제가 하는 여러 일들 가...

blog.naver.com

반응형

'프로그래밍 > CS' 카테고리의 다른 글

[CS] 인터럽트  (0) 2024.10.22
[CS] CPU 스케줄링  (4) 2024.10.21
[CS] CPU의 메모리 계층 구조  (4) 2024.10.13
[CS] 커널(Kernel)과 그 종류에 대해  (0) 2024.10.13
[CS] 프로세스와 스레드  (2) 2024.10.06
반응형

유피의 소원


소개

장르 2D 횡스크롤 액션 플랫포머
작업 기간 2주
작업 인원 4명
언어 C++
사용 라이브러리 WinAPI, GDI+, FMOD

게임인재원 6기 1학기때 5월 중순부터 2주간 진행한 미니프로젝트 작품입니다. (그걸 왜 이제 올리는데)

WinAPI를 기반으로 GDI+ 그래픽 라이브러리를 사용해 개발했습니다.

기획 3명, 아트 2명, 프로그래밍 4명으로 진행되었습니다.


구현

총 4명의 프로그래밍 팀원이 작업했습니다.

엔진이라고 하긴 뭐하지만... 개발 당시에 어느정도 엔진 흉내는 내던 저의 엔진을 사용해 작업을 했습니다. 

 

 


클라이언트 사이드에선

캐릭터, 상호작용 오브젝트를 구현했으며, 외에 자잘하게 막힌 부분이나 버그 등을 수정하였습니다.


클라이언트 주요 구현 부분
  • 캐릭터의 중력과 타일 충돌에 대한 구현
  • 캐릭터의 대쉬, 우산조작, 밧줄타기, 벽타기 등의 액션 구현
  • 액션에 맞는 상호작용 오브젝트(로프, 레이저)들에 대한 구현
엔진 사이드에선
추가적으로 엔진에 부족한 기능을 추가하거나 버그 등을 수정하였습니다.

엔진 주요 구현 부분
  • 렌더링(애니메이션, 텍스트 등)관련 부분과 충돌 콜라이더, 트랜스폼 등을 컴포넌트로 묶음.
  • 인풋, 타임, 사운드 등과 같은 시스템 구현.
  • 그 외에 씬, 오브젝트의 구조 설계 및 구현

플레이 사진


아쉬운 점

지금이야 과거형이라 상당수 고쳤지만 그때 느꼈던 아쉬운 점을 남겨본다....

 

1. 객체의 생성과 삭제 주기 : 객체의 생성과 삭제 주기에 대한 설정이 없이, 바로 생성되고 바로 삭제되서 런타임 중에 버그가 발생하거나 크래쉬가 났던 버그... 막바지에 고치기가 힘들어서 대충 하드코딩으로 땜빵했는데 정말 불편했다.

2. 데이터 접근 : 클래스의 멤버변수를 무지성으로 static과 public으로 남발했다. 구현할 때는 편하지만 정말 안좋은 습관인거 같다.

3. 그래픽 라이브러리에 대한 낮은 이해도 : GDI+는 GPU를 사용하지 않는 그래픽 라이브러리라 속도가 매우 느리다. 이 점을 간과하고 제작했던 점.(렉이 상당했다. 그나마 줄이고 줄인게 이 정도)

4. 스프라이트 리소스에 대한 아쉬운 처리 : 저 때 스프라이트 출력 방식은 스프라이트를 전부 컷팅해놓고 쓴게 아니라, 스프라이트 사진을 렌더링할때마다 일부 영역만 렌더링하게 만들었다. 일부 영역만 렌더링하는 것에 대한 부하가 많이 심하다는 것을 깨달은 것은 상당히 충격적이었다...

반응형
반응형

하이 헬로 봉쥬르?

오늘은 프로세스와 스레드에 대해 글을 써보겠읍니다.


프로그램과 프로세스의 차이


본론으로 들어가기 전에 프로그램과 프로세스의 차이를 먼저 간단하게 짚고 넘어가보려고 합니다. (제가 헷갈렸던 개념이었기 때문)

프로그램과 프로세스는 CPU 메모리상에 로드가 되어있냐, 안되어있냐로 나눌 수 있습니다. 프로그램과 프로세스를 간단히 요약해보자면,

프로그램은 실행 가능한 코드의 묶음입니다. 즉, 실행되기 전의 정적 상태로, 디스크에 저장된 실행 파일(exe 등)을 말합니다. 

프로세스는 프로그램이 실행되어 운영체제에 의해 독립적인 메모리를 할당받고, 실제로 실행되고 있는 동적 상태로, 메모리에 올라가 CPU에서 처리 중인 작업입니다.

 

프로그램을 실행하면 하나의 메인 프로세스가 생성이 되며, 메인 프로세스를 통해 자식 프로세스를 생성할 수 있습니다.

 

 

위 사진처럼 메모장이라는 프로그램을 두 번 실행했습니다. 그렇다면 프로그램과 프로세스는 각각 몇 개일까요?
정답은 프로그램은 하나, 프로세스는 두 개 혹은 그 이상입니다!


프로세스와 스레드를 자세히 알아보자


1. 프로세스 ID (PID)

운영체제는 수많은 프로세스를 어떻게 구분하여 관리할까요?

운영체제는 각 프로세스마다 프로세스 테이블에 데이터를 저장하는데요, 이 테이블에는 각 프로세스의 상태, PID, 할당된 메모리 등의 정보가 저장됩니다.

그중 프로세스 ID (PID)를 통해 프로세스를 구분 합니다.

각 프로세스의 PID가 다른 모습을 볼 수 있다.

 

운영체제는 이 ID를 통해 각 프로세스에 접근하여 상태, 메모리 등을 관리하게 됩니다.


2. 프로세스의 주소 공간

 

 

 

프로세스는 앞서 운영체제에 의해서 독립적인 메모리 공간을 할당받는다고 말했습니다.

운영체제는 한정된 공간에서 메모리를 최대한 효율적으로 관리하기 위해 메모리 영역을 4개로 나눴습니다.

프로세스의 주소 공간.jpg

위와 같이 스택, 힙, 데이터, 코드 총 4개의 영역이 있습니다. 각 영역에 대해 간단하게 알아보자면,

 

  • 스택(Stack): 자동으로 관리되는 메모리 영역입니다. 함수가 호출될 때마다 필요한 메모리 공간을 위에 차곡차곡 쌓은 후, 함수가 종료될 때마다 차례대로 메모리를 해제합니다. 때문에 단편화 현상이 일어날 일이 없고, 메모리 할당 및 해제의 오버헤드가 적습니다.
  • 힙(Heap): 수동으로 관리되는 메모리 영역입니다. 개발자가 필요할 때 메모리 영역을 할당받고, 다 쓰면 직접 메모리를 해제하는 방식입니다. 각 메모리의 수명이 다르기 때문에 단편화 현상이 일어나고, 그에 따른 성능 저하가 발생할 수 있습니다.
  • 데이터(Data): 전역 변수와 정적 변수가 저장되는 메모리 영역입니다. 프로그램의 시작 시 한 번만 할당되고, 프로그램이 종료될 때까지 유지되므로, 메모리 할당 및 해제의 오버헤드가 줄어듭니다. 데이터 영역의 메모리는 모든 함수에서 접근 가능하므로, 필요한 데이터를 쉽게 관리할 수 있습니다.
  • 코드(Code): 실행할 프로그램의 기계어 코드가 저장되는 메모리 영역입니다. 보통 읽기 전용으로 설정되어 있어 코드의 무결성을 보장합니다. 코드가 한 곳에 모여 있으면 캐시 히트율이 올라가기 때문에, 성능이 향상될 수 있습니다.

 

 

이처럼, 프로세스의 각 주소 공간들은 역할이 명확이 구분되어 있습니다. 또한 성능과 안정성 등 많은 측면에서 중요한 역할을 하기 때문에 각 역할을 이해하고 잘 쓰는게 중요합니다.


3. 프로세스의 스레드

공장이 노동자의 노동력에 의해 굴러가는 것처럼 프로세스도 일꾼이 있습니다.

그것이 바로 스레드(Thread)입니다.

출처 : 나무위키 (...)

스레드는 많은 특징을 가지고 있습니다. 나열해보면,

  1. 프로세스는 최소 한 개 이상의 스레드를 가지며, 이를 메인 스레드라고 합니다.
  2. 메인 스레드를 통해 자식 스레드를 만들 수 있습니다.
  3. 각 스레드는 자신만의 독립적인 스택 메모리 영역을 할당받습니다.
  4. 대신, 그 외의 프로세스 메모리 영역은 공유하여 사용할 수 있습니다.
  5. 반대로, 각 스레드는 서로의 스택 메모리 영역에 접근할 수 없습니다.

한 프로세스 내에 여러 스레드가 존재할 수 있으며, 이를 멀티스레드 기법이라고 합니다. 부하가 큰 작업을 여러 스레드가 나눠 처리하거나, 각 역할의 코드를 독립적으로 실행시키고 싶을 때 사용하는 기법입니다.


멀티 프로세스, 멀티 스레드?

앞서 설명했듯이 프로세스와 스레드는 여러 개 존재할 수 있습니다. 사실 서로의 용도가 다르기 때문에 정확히 무슨 차이가 있을까요?
차이점을 알기 전에 알아야 할 개념이 있습니다. 바로 동시성, 병렬성, 컨텍스트 스위칭입니다.


1. 동시성과 병렬성

멀티 프로세스와 멀티 스레드의 공통점은 동시에 실행된다는 점입니다. 여기서 "동시"라는 용어는 두 가지 의미를 내포하고 있습니다.

  • 동시성(Concurrency): 짧은 시간 동안 여러 작업이 수행되어 마치 동시에 여러 작업이 진행되고 있는 것처럼 보이게 하는 것을 의미합니다.
  • 병렬성(Parallelism): 실제로 여러 작업이 동시에 수행되고 있는 상태를 의미합니다.

 


2. 컨텍스트 스위칭(Context Switching)

앞서 동시성에 대해 알아본 이유는 CPU의 특성때문입니다. 왤까요?

그렇습니다... CPU는 한 번에 여러 프로세스를 처리할 수 없습니다. 때문에 한 CPU가 여러 프로세스를 다루려면 프로세스1을 처리하고 프로세스2로 넘어가는 작업을 거쳐야 하는데요. 여기서 CPU가 다음 프로세스에게 작업 제어권을 주는 것을 컨텍스트 스위칭이라고 합니다. 

이처럼 CPU가 여러 프로세스의 작업을 처리하는 것을 시분할 시스템이라고 부릅니다.

CPU가 프로세스를 처리할 때 효율적인 분담을 위해 스케줄링을 하게 되는데.... 이건 길어지니까 나중에 쓰겠읍니다..

 

컨텍스트 스위칭의 중요한 점은 오버헤드가 일어난다는 점입니다.

CPU가 다른 프로세스의 작업을 하기 위해선, 프로세스의 정보(레지스터 값, 프로그램 카운터, 스택 포인터 등)를 저장 및 불러오는 과정을 거칩니다. 또한 스케줄링 판별, 캐시 미스 등의 많은 이유로 오버헤드가 일어나게 됩니다.

때문에 잦은 컨텍스트 스위칭은 성능저하를 일으킬 수 있습니다.

때문에 Core(CPU)의 수가 적을수록 컨텍스트 스위칭이 자주 일어나며 오버헤드가 일어나게 됩니다.


3. 멀티 프로세스

멀티 프로세스란 2개 이상의 프로세스가 동시에 실행되는 것을 말합니다.

이때 CPU가 여러 프로세스의 작업을 번갈아 가면서 처리하게 되는데, 이 때문에 동시성(Concurrency)이 높습니다.

멀티 프로세스의 특징은 다음과 같습니다.

 

  • 각 프로세스 간의 독립성이 보장됩니다. 여기서 독립성은 메모리 공간 등을 의미합니다.
  • 각 프로세스는 서로의 메모리를 침범하지 못합니다.
  • 한 프로세스가 장애를 일으켜도 나머지 프로세스들은 영향을 받지 않습니다.
  • 프로세스 간에 컨텍스트 스위칭(Context Switching)이 빈번하게 일어나게 됩니다. 이로 인한 오버헤드가 발생할 수 있습니다.
  • 프로세스 생성과 메모리 할당 과정에서 시스템 콜이 발생해 오버헤드가 일어납니다.

 

4. 멀티 스레드

멀티 스레드는 한 프로세스에 2개 이상의 스레드가 작업을 하는 것을 말합니다.
실제로 여러 스레드가 동시에 작업을 하므로, 병렬성(Parallelism)을 높일 수 있습니다.

멀티 스레드의 특징은 다음과 같습니다.

 

  • 각 스레드는 서로 자원을 공유할 수 있어 데이터를 주고받기가 편리합니다.
  • 동시 요청을 처리할 수 있습니다.
  • 한 스레드가 데이터를 쓰는 동안 다른 스레드가 읽는 경우 의도치 않은 오류가 발생할 수 있습니다.
  • 프로세스 생성과 메모리 할당 과정이 필요하지 않아 오버헤드가 비교적 적습니다.

주의할 점은 멀티 스레드는 싱글 코어 환경에서 동시에 작업이 안된다는 점이다...

때문에 싱글 코어에서의 멀티 스레드는 성능향상을 꾀할 수 없다.

반응형

'프로그래밍 > CS' 카테고리의 다른 글

[CS] 인터럽트  (0) 2024.10.22
[CS] CPU 스케줄링  (4) 2024.10.21
[CS] CPU의 메모리 계층 구조  (4) 2024.10.13
[CS] 커널(Kernel)과 그 종류에 대해  (0) 2024.10.13
[CS] 유저영역, 커널영역 그리고 SystemCall  (1) 2024.10.13
반응형

ㅎㅇ 헬로 반갑습니다?

다음 포스팅 주제로 비트연산에 대해 적으려 했는데, 자료조사좀 하던 도중에 재밌는 거를 발견해서 비트연산 포스팅 이전에 미리 글하나를 써보려고 합니당


 2진 리터럴(Binary literals)이 뭔가요? 이 10덕아

넵, 2진 리터럴은 말그대로 2진 리터럴입니다(?) (퍽퍽

그전에 리터럴에 대해 초간단으로 말씀드리면, 그냥 우변에 올 수 있는 데이터? 같은 느낌입니다 ㅇㅅㅇ. 나중에 이것도 글로 써야겠다.

그런 데이터, 즉 리터럴들을 컴퓨터가 구분하기 위해 저희는 리터럴 표기법이라는 것을 써주는데요? 사실 당연하게 써왔던 것들입니다. 무서워하지 마시죠 크크 (퍽퍽

int num1 = 0x12; // 16진수를 나타내기 위해 0x를 붙임
float num2 = 1.0f; // float를 나타내기 위해 f를 붙임
const char* str = "Hello World"; // 문자열을 나타내기 위해 ""을 붙임

근데? C++11까지는 2진수에 대한 리터럴표기법이 없었습니다. (OTL)

C++14에 2진수에 대한 리터럴 표기법이 나왔다고 합니다. 그게 바로 2진 리터럴인데요 ㅇㅅㅇ.

표기도 간단합니다. 바로 보시져 ㄱ_ㄱ

// 2진 리터럴 표기
int bit = 0b1010; // 2진수를 나타내기 위해 0b를 붙임

마우스 올리면 숫자도 바로 알려줌 ㅋㅋ


이게 끝입니다.... 

사용자 정의 리터럴을 만들 수 있다는 흥미로운 사실을 발견했는데 그건 다음에 시간이 되면 포스팅해보겠습니다?...

그럼 20000

반응형

+ Recent posts