자식 프로세스의 메모리 공간

2019. 5. 9. 14:44임베디드/리눅스시스템프로그래밍

커널은 자식 프로세스가 생성되면 프로세스 테이블에 등록하고 메모리를 할당한다. 일반적으로 프로세스가 생성되면, 자식 프로세스와 부모 프로세스는 텍스트(text, 프로그램 코드) 영역은 공유하고, 데이터, 힙, 스택 영역은 복사하는데, 보통 fork() 함수를 수행한 후 바로 exec 함수가 호출되기 때문에 대부분의 시스템에서 fork() 함수 수행 시 데이터, 힙, 스택 영역을 바로 복사하지 않는다. 자식 프로세스의 내용이 변경될 때 나머지 영역을 복사하는 방법을 통해서 실행 속도를 높일 수 있는데 이를 변형 시에 복사(copy-on-write, COW)라고 한다

 

*실제 하나의 프로세스 당 생성되는 가상 주소 공간이 4G 생성된다. 따라서 작은 영역이 아니기 때문에 섣불리 같은 코드를 공유한다면 복사할 필요가 없고 부모 프로세스 변경 시에만 복사를 하면 된다

 

fork() 함수의 수행 후 exec() 함수를 바로 호출한다면 부모 프로세스의 text 영역을 복사하는 작업은 불필요하게 된다. 이를 위해 vfork() 함수를 제공하고 있는데, vfork() 함수는 exec()함수를 통해서 새로운 프로그램을 실행시킬 목적으로 자식 프로세스를 생성할 때 부모 프로세스를 생성할 때 부모 프로세스의 메모리 영역을 모두 복사하지 않는다. 따라서 vfork()로 생성한다면 exec() 실행 전에 같은 메모리를 공유하게 된다 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
 
static int g_var = 1;
char str[] = "PID";
 
int main(int argc, char **argv) {
    int var;
    pid_t pid;
    var = 88;
 
    pid = vfork();
    if(pid < 0) {
        perror("vfork()");
    } 
    else if(pid == 0) {
        g_var++;
        var++;
        printf("Parent %s from Child Process(%d) : %d\n",
                str, getpid(), getppid());
        printf("pid = %d, Global var = %d, var = %d\n", getpid(), g_var, var);
        _exit(0);
    }
    else {
        printf("Child %s from Parent Process(%d) : %d\n", str, getpid(), pid);
    }
 
    printf("pid = %d, Global var = %d, var = %d\n", getpid(), g_var, var);
    return 0;
}
cs

 

1
2
3
4
Parent PID from Child Process(10050) : 10049
pid = 10050, Global var = 2, var 89
Child PID from Parent Process(10049) : 10050
pid = 10049, Global var = 2, var = 89
cs

 

* 수정

리눅스에서 도입한 copy-on-write 기법을 도입한 이후로 vfork()의 성능개선은 이제 큰 차이를 발생시키지 않기에 fork() 사용을 더 권장한다

'임베디드 > 리눅스시스템프로그래밍' 카테고리의 다른 글

main의 argv 첫번째 인자  (0) 2019.05.09
exit와 _exit의 차이  (0) 2019.05.09
fork()후 자식프로세스의 시작과 마지막  (0) 2019.05.09
좀비 프로세스  (0) 2019.05.08
inotify 예제  (0) 2019.05.01