# 고급 메모리 관리 기법

## 1. 개요

Xenomai 시스템의 성능을 최적화하기 위해서는 메모리 관리 기법이 매우 중요하다. 적절한 메모리 관리 기법을 사용하면 응용 프로그램의 실행 속도와 안정성을 크게 향상시킬 수 있다. 여기에서는 Xenomai에서 사용할 수 있는 다양한 고급 메모리 관리 기법에 대해 설명한다.

## 2. 페이지 잠금

페이지 잠금은 특정 메모리 영역을 물리 메모리에 고정하여 페이지 폴트가 발생하지 않도록 하는 기법이다. 디스크 I/O를 줄이고 실시간 성능을 보장하는 데 유용하다. 다음과 같은 함수들을 사용하여 페이지를 잠글 수 있다:

```c
#include <sys/mman.h>

void lock_memory(void) {
    if(mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
        perror("mlockall");
        exit(1);
    }
}
```

## 3. 메모리 풀

메모리 풀은 미리 할당된 메모리 블록을 필요할 때 사용할 수 있게 관리하는 방식이다. 메모리 할당 및 해제의 오버헤드를 줄이는 데 유용하다. Xenomai에서는 `rtdm_mempool` 인터페이스를 제공하여 메모리 풀이 관리된다.

### 메모리 풀 초기화 예제:

```c
#include <rtdm/rtdm.h>
#include <stdlib.h>

#define POOL_SIZE 1024
#define BLOCK_SIZE 64

static rtdm_mempool_t pool;

void init_mempool(void) {
    if (rtdm_mempool_init(&pool, POOL_SIZE, BLOCK_SIZE, RTDM_MEM_NORMAL) < 0) {
        perror("rtdm_mempool_init");
        exit(1);
    }
}

void* alloc_block() {
    return rtdm_mempool_alloc(&pool);
}

void free_block(void *block) {
    rtdm_mempool_free(&pool, block);
}
```

## 4. 캐시 친화적 데이터 구조

캐시 친화적인 데이터 구조를 사용하면 캐시 미스(cache miss)를 최소화할 수 있다. 이 기법을 통해 메모리 접근 시간을 줄이고 성능을 개선할 수 있다.

### 배열 대신 구조체 예제:

```c
struct data {
    int member[256];
};

// 비캐시 친화적 접근
void non_cache_friendly(struct data *d) {
    for (int i = 0; i < 256; i++) {
        d->member[i] = i;
    }
}

struct data_in_cache_line {
    int member;
};

// 캐시 친화적 접근
void cache_friendly(struct data_in_cache_line *dicl) {
    for (int i = 0; i < 256; i++) {
        dicl[i].member = i;
    }
}
```

위 코드에서 첫 번째 함수는 비연속적인 메모리 접근을 수행하여 캐시 미스를 유발할 가능성이 높다. 두 번째 함수는 더 나은 캐시 적중률을 가지는 연속적인 메모리 접근을 한다.

## 5. NUMA(Non-Uniform Memory Access) 관리

NUMA 아키텍처에서는 모든 메모리 접근이 동일한 속도로 이루어지지 않는다. 특정 프로세서가 특정 메모리에 빠르게 접근할 수 있도록 관리하는 것이 중요하다. 이를 위해 Xenomai에서는 `numactl`과 같은 도구를 사용할 수 있다.

### 메모리 할당 예제:

```bash
numactl --membind=0 ./your_xenomai_app
```

위 명령은 특정 NUMA 노드(예: 노드 0)의 메모리를 사용하도록 지정한다.

## 6. 적합한 메모리 할당 정책 사용

리눅스에는 여러 가지 메모리 할당 정책이 있다. 이를 통해 필요한 경우 특정 메모리 할당 정책을 적용할 수 있다. Xenomai RTDM 사용 시에도 적용할 수 있다.

### 노드 선호 메모리 할당

```bash
numactl --preferred=0 ./your_xenomai_app
```

위 명령은 특정 NUMA 노드에 선호도를 두는 메모리 할당을 진행한다.

## 7. CPU-Affinity 설정

실시간 시스템에서는 프로세스나 스레드를 특정 CPU 코어에 고정시키는 것이 중요하다. 이를 통해 캐시 미스를 줄이고 스케줄링 지연을 방지할 수 있다.

### CPU-Affinity 설정 예제:

```c
#include <pthread.h>
#include <sched.h>

void set_cpu_affinity(int cpu) {
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(cpu, &cpuset);

    pthread_t current_thread = pthread_self();
    if (pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset) != 0) {
        perror("pthread_setaffinity_np");
    }
}
```

위 함수를 통해 특정 CPU 코어에 현재 스레드를 고정할 수 있다.

## 8. 실시간 스케줄러

Xenomai는 여러 종류의 실시간 스케줄러를 제공한다. 대표적으로 `Cobalt`와 `Mercury` 스케줄러가 있다. 작업에 적합한 스케줄러를 선택하고, 리눅스의 비선형 스케줄링 정책과 충돌하지 않도록 조정해야 한다.

### Cobalt 실시간 정책 설정 예제:

```c
#include <alchemy/task.h>

void set_cobalt_policy(int priority) {
    RT_TASK task;
    rt_task_shadow(&task, NULL, priority, T_CPU(0));
}
```

위 코드는 Cobalt 스케줄러를 사용하여 특정 우선순위를 설정하는 예제이다.

## 9. 우선순위 상속 프로토콜

Xenomai는 우선순위 상속 프로토콜을 지원하여 우선순위 반전 문제를 해결한다. 이를 통해 높은 우선순위의 작업이 낮은 우선순위의 작업에 의해 지연되지 않도록 할 수 있다.

### 우선순위 상속 설정 예제:

```c
#include <pthread.h>

void create_mutex_with_priority_inheritance(pthread_mutex_t *mutex) {
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
    pthread_mutex_init(mutex, &attr);
}
```

위 함수는 우선순위 상속이 적용된 뮤텍스를 생성하는 예제이다.

## 10. 기존 리소스의 명시적 해제

Xenomai 애플리케이션에서 리소스를 할당한 후 이를 명시적으로 해제하는 일은 매우 중요하다. 특히 메모리 누수, 파일 디스크립터 누수 등을 방지한다.

### 명시적 리소스 해제 예제:

```c
void cleanup() {
    // 할당된 메모리 해제
    if (allocated_memory) {
        free(allocated_memory);
    }

    // 파일 디스크립터 닫기
    if (file_descriptor >= 0) {
        close(file_descriptor);
    }

    // 기타 자원 해제 코드
}
```

위 코드는 사용된 리소스를 명시적으로 해제하는 예제에 해당된다.

***

이와 같이 다양한 고급 메모리 관리 기법을 잘 활용하면 Xenomai 실시간 시스템의 성능을 최대한으로 이끌어낼 수 있다.
