Linux 7.0 기준 · 마지막 갱신: 2026-06-26
ARM64와 x86_64는 Linux 커널에서 메모리 관리를 구현하는 아키텍처입니다. 두 아키텍처는 공통적으로 4단계 또는 5단계 페이지 테이블을 사용하지만, 하드웨어 설계 철학이 다르기에 세부 구현에서 상당한 차이가 발생합니다. x86_64는 강력한 일관성(Coherent) 메모리 모델을 기반으로 하여 소프트웨어가 명시적 배리어를 적게 사용하는 반면, ARM64는 강건한(Relaxed) 일관성 모델을 사용하므로 드라이버와 커널 코드에서 명시적 메모리 배리어를 더 많이 사용해야 합니다.
이 문서에서는 Linux 7.0 소스 코드를 기반으로 두 아키텍처의 메모리 관리 차이점을 분석합니다. 페이지 테이블 구조, TLB 관리, 메모리 배리어, Huge Page 지원, DMA 코히어런스, NUMA 구현 등 핵심 영역을 다룹니다. 각 아키텍처별 특성을 이해하면 커널 코드 최적화와 드라이버 개발에 큰 도움이 됩니다.
일상 비유로 보면 각 프로세스는 자기만의 도서관 지도(VA)를 들고 있고, MMU가 그 지도를 실제 서가(PA)로 바꿉니다. ARM64는 안내판을 더 자주 다시 붙여야 하는 쪽이고, x86_64는 기본 질서를 더 강하게 유지하는 쪽이라고 보면 이해가 쉽습니다.
소스 파일 경로:
arch/arm64/include/asm/pgtable.h ← ARM64 페이지 테이블
arch/arm64/include/asm/pgtable-hwdef.h ← ARM64 페이지 테이블 하드웨어 정의
arch/arm64/include/asm/tlbflush.h ← ARM64 TLB 플러시
arch/arm64/include/asm/barrier.h ← ARM64 메모리 배리어
arch/arm64/include/asm/memory.h ← ARM64 메모리 맵
arch/arm64/include/asm/hugetlb.h ← ARM64 HugeTLB
arch/x86/include/asm/pgtable.h ← x86_64 페이지 테이블
arch/x86/include/asm/pgtable_types.h ← x86_64 페이지 테이블 타입
arch/x86/include/asm/pgtable_64.h ← x86_64 페이지 테이블 (64비트)
arch/x86/include/asm/tlb.h ← x86_64 TLB 관리
arch/x86/include/asm/tlbflush.h ← x86_64 TLB 플러시
arch/x86/include/asm/barrier.h ← x86_64 메모리 배리어
# 현재 시스템 아키텍처 확인
uname -m
# 페이지 테이블 레벨 확인 (CONFIG_PGTABLE_LEVELS)
cat /boot/config-$(uname -r) | grep PGTABLE_LEVELS
# Huge Page 지원 확인
cat /proc/meminfo | grep -i huge
# NUMA 노드 정보 확인
numactl --hardware
# 메모리 배리어 관련 커널 심볼 확인
cat /proc/kallsyms | grep -E "dsb|dmb|isb|mfence|lfence|sfence"
# 페이지 크기 확인
getconf PAGESIZE
# 커널 설정에서 아키텍처 관련 옵션 확인
cat /boot/config-$(uname -r) | grep -E "ARM64|X86"
# TLB 관련 정보 확인
dmesg | grep -i tlb
# 메모리 맵 확인
cat /proc/iomem | head -20
# DMA 관련 정보 확인
cat /proc/dma
# 페이지 폴트와 메모리 압력 확인
cat /proc/vmstat | grep -E "pgfault|pgmajfault"
cat /proc/pressure/memory
# 아키텍처별 페이지 테이블 덤프 확인 (debugfs 활성화 시)
sudo cat /sys/kernel/debug/kernel_page_tables | head -40
ARM64 PTE는 64비트 엔트리로 다양한 플래그를 포함합니다.
// arch/arm64/include/asm/pgtable-hwdef.h:164-176
#define PTE_VALID (_AT(pteval_t, 1) << 0) // 유효 비트
#define PTE_USER (_AT(pteval_t, 1) << 6) // AP[1] - 사용자 접근 가능
#define PTE_RDONLY (_AT(pteval_t, 1) << 7) // AP[2] - 읽기 전용
#define PTE_SHARED (_AT(pteval_t, 3) << 8) // SH[1:0] - 내부 공유 가능
#define PTE_AF (_AT(pteval_t, 1) << 10) // 접근 플래그
#define PTE_NG (_AT(pteval_t, 1) << 11) // 비전역 플래그
#define PTE_DBM (_AT(pteval_t, 1) << 51) // 더티 비트 관리
#define PTE_CONT (_AT(pteval_t, 1) << 52) // 연속 범위
#define PTE_PXN (_AT(pteval_t, 1) << 53) // 특권 실행 불가
#define PTE_UXN (_AT(pteval_t, 1) << 54) // 사용자 실행 불가
특징:
PTE_DBM: 하드웨어 더티 비트 관리 (ARM64 고유)PTE_CONT: 연속 페이지 매핑 (성능 최적화)PTE_UXN: NX 비트와 유사하지만 실행 불가 영역 분리 가능x86_64 PTE는 64비트 엔트리로 NX 비트와 다양한 소프트웨어 비트를 포함합니다.
// arch/x86/include/asm/pgtable_types.h:51-58
#define _PAGE_PRESENT (_AT(pteval_t, 1) << _PAGE_BIT_PRESENT) // 존재 비트
#define _PAGE_RW (_AT(pteval_t, 1) << _PAGE_BIT_RW) // 읽기/쓰기
#define _PAGE_USER (_AT(pteval_t, 1) << _PAGE_BIT_USER) // 사용자 접근
#define _PAGE_PWT (_AT(pteval_t, 1) << _PAGE_BIT_PWT) // 페이지 쓰기 통과
#define _PAGE_PCD (_AT(pteval_t, 1) << _PAGE_BIT_PCD) // 페이지 캐시 비활성화
#define _PAGE_ACCESSED (_AT(pteval_t, 1) << _PAGE_BIT_ACCESSED) // 접근됨
#define _PAGE_DIRTY (_AT(pteval_t, 1) << _PAGE_BIT_DIRTY) // 더티
#define _PAGE_PSE (_AT(pteval_t, 1) << _PAGE_BIT_PSE) // Huge Page
특징:
_PAGE_NX: 실행 불가 비트 (bit 63)_PAGE_PSE: Huge Page 지원_PAGE_PAT: 페이지 속성 테이블_PAGE_SOFT_DIRTY: 소프트웨어 더티 트래킹ARM64는 MAIR (Memory Attribute Indirection Register)를 사용하여 메모리 속성을 정의합니다.
// arch/arm64/include/asm/memory.h:171-176
#define MT_NORMAL 0 // 일반 메모리 (WB, 캐시 가능)
#define MT_NORMAL_TAGGED 1 // 태그된 일반 메모리 (MTE용)
#define MT_NORMAL_NC 2 // 비캐시 메모리
#define MT_DEVICE_nGnRnE 3 // 디바이스 메모리 (강건한 Ordering)
#define MT_DEVICE_nGnRE 4 // 디바이스 메모리 (약한 Ordering)
x86_64는 PAT (Page Attribute Table)와 MTRR를 사용하여 캐시 모드를 관리합니다.
// arch/x86/include/asm/pgtable_types.h:167-176
enum page_cache_mode {
_PAGE_CACHE_MODE_WB = 0, // Write-Back
_PAGE_CACHE_MODE_WC = 1, // Write-Combining
_PAGE_CACHE_MODE_UC_MINUS = 2, // Uncached minus
_PAGE_CACHE_MODE_UC = 3, // Uncached
_PAGE_CACHE_MODE_WT = 4, // Write-Through
_PAGE_CACHE_MODE_WP = 5, // Write-Protect
_PAGE_CACHE_MODE_NUM = 8
};
// arch/arm64/include/asm/tlbflush.h:32-42
#define __TLBI_0(op, arg) asm (ARM64_ASM_PREAMBLE \
"tlbi " #op "\n" \
: : )
#define __TLBI_1(op, arg) asm (ARM64_ASM_PREAMBLE \
"tlbi " #op ", %x0\n" \
: : "rZ" (arg))
#define __TLBI_N(op, arg, n, ...) __TLBI_##n(op, arg)
#define __tlbi(op, ...) __TLBI_N(op, ##__VA_ARGS__, 1, 0)
특징: ARM64는 TLBI 명령어를 사용하여 브로드캐스트 방식으로 TLB를 무효화합니다.
// arch/x86/include/asm/tlb.h:26-29
static inline void invlpg(unsigned long addr)
{
asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
}
특징: x86_64의 기본 경로는 invlpg로 개별 페이지를 무효화하며, 일부 확장 경로에서는 INVLPGB 같은 범위 무효화도 다룹니다.
// arch/arm64/include/asm/barrier.h:27-29, 63-65
#define isb() asm volatile("isb" : : : "memory")
#define dmb(opt) asm volatile("dmb " #opt : : : "memory")
#define dsb(opt) asm volatile("dsb " #opt : : : "memory")
#define __mb() dsb(sy)
#define __rmb() dsb(ld)
#define __wmb() dsb(st)
특징: ARM64는 명시적 배리어 명령어를 사용하여 메모리 일관성을 보장합니다.
// arch/x86/include/asm/barrier.h:22-24
#define __mb() asm volatile("mfence":::"memory")
#define __rmb() asm volatile("lfence":::"memory")
#define __wmb() asm volatile("sfence" ::: "memory")
특징: x86_64는 강건한 메모리 모델을 사용하므로 많은 경우 배리어가 불필요합니다.
// arch/arm64/include/asm/hugetlb.h:35-36
pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags);
#define arch_make_huge_pte arch_make_huge_pte
특징: ARM64는 PTE_CONT 비트를 사용하여 연속 페이지 매핑을 최적화합니다.
do_page_fault()
→ do_mem_abort()
→ do_translation_fault()
→ handle_mm_fault()
→ __handle_mm_fault()
→ handle_pte_fault()
→ do_anonymous_page() // 익명 페이지
→ do_fault() // 파일 기반 페이지
→ do_wp_page() // COW (Copy-on-Write)
→ do_numa_page() // NUMA 페이지
exc_page_fault()
→ do_user_addr_fault()
→ handle_mm_fault()
→ __handle_mm_fault()
→ handle_pte_fault()
→ do_anonymous_page() // 익명 페이지
→ do_fault() // 파일 기반 페이지
→ do_wp_page() // COW (Copy-on-Write)
→ do_numa_page() // NUMA 페이지
차이점: ARM64는 do_mem_abort()를 통해 하드웨어 폴트를 처리하고, x86_64는 exc_page_fault()를 통해 인터럽트 기반으로 처리합니다.
두 경로 모두 결국 handle_mm_fault()로 모이고, 이후에는 do_anonymous_page(), do_fault(), do_wp_page(), do_numa_page() 같은 공통 처리로 갈라집니다. minor fault는 PTE만 채우는 경우가 많고, major fault는 파일 I/O를 동반하며, 권한 위반이나 잘못된 주소는 SIGSEGV로 끝납니다.
| 항목 | ARM64 | x86_64 |
|---|---|---|
| **페이지 테이블 레벨** | 4단계 (VA_BITS=48) 또는 5단계 (VA_BITS=52) | 4단계 (4-level) 또는 5단계 (5-level, LA57) |
| **페이지 크기** | 4KB, 16KB, 64KB 선택 가능 | 4KB 고정 (2MB Huge, 1GB Huge) |
| **PTE 비트 수** | 64비트 (50비트 물리 주소) | 64비트 (52비트 물리 주소) |
| **NX 비트** | PTE_UXN, PTE_PXN (2비트) | _PAGE_NX (1비트) |
| **더티 비트** | 하드웨어 지원 (PTE_DBM) | 하드웨어 지원 (_PAGE_DIRTY) |
| **접근 플래그** | PTE_AF | _PAGE_ACCESSED |
| 항목 | ARM64 | x86_64 |
|---|---|---|
| **TLB 플러시 명령어** | TLBI (브로드캐스트) | invlpg (기본, 개별 페이지) |
| **무효화 범위** | ASID 기반, 페이지/테이블/전체 | PCID/ASID 기반, 페이지/전체 |
| **동기화** | DSB + ISB 필요 | TLBSYNC 필요 |
| **레이지 모드** | TIF_LAZY_MMU_PENDING 지원 | 없음 |
| **성능** | 브로드캐스트 오버헤드 발생 가능 | 로컬 처리 우선 |
| 항목 | ARM64 | x86_64 |
|---|---|---|
| **메모리 모델** | 강건한 (Relaxed) | 강력한 (Strong) |
| **전체 배리어** | DSB SY | MFENCE |
| **읽기 배리어** | DSB LD | LFENCE |
| **쓰기 배리어** | DSB ST | SFENCE |
| **DMA 배리어** | DMB OSH | barrier() (불필요) |
| **명령어 동기화** | ISB | 없음 |
| 항목 | ARM64 | x86_64 |
|---|---|---|
| **THP 크기** | 2MB (PMD), 연속 PTE (CONT_PTE) | 2MB (PMD), 1GB (PUD) |
| **연속 매핑** | PTE_CONT (16페이지), PMD_CONT (128페이지) | 없음 |
| **Contiguous 비트** | 하드웨어 지원 (PTE_CONT) | 없음 |
| ** HugeTLB** | 기본 지원 | 기본 지원 |
| 항목 | ARM64 | x86_64 |
|---|---|---|
| **DMA 일관성** | IOMMU 또는 하드웨어 코히어런스 | 하드웨어 코히어런스 |
| **배리어** | DMB OSH (DMA 배리어) | barrier() (불필요) |
| **IOMMU** | SMMU (System MMU) | VT-d, AMD-Vi |
| **DMA 영역** | DMA 영역 할당 지원 | DMA 영역 할당 지원 |
| 항목 | ARM64 | x86_64 |
|---|---|---|
| **NUMA 구현** | ACPI SRAT 또는 DT | ACPI SRAT |
| **거리 계산** | 추상 거리 모델 | ACPI SLIT |
| **자동 NUMA** | AutoNUMA 지원 | AutoNUMA 지원 |
| **메모리 정책** | 기본 정책 + NUMA 정책 | 기본 정책 + NUMA 정책 |
# 1. 아키텍처별 페이지 테이블 레벨 확인
# ARM64
cat /proc/cpuinfo | grep -i "page table"
# x86_64
cat /proc/cpuinfo | grep -i "pge\|pse\|pdpe1gb"
# 2. Huge Page 설정 확인
cat /proc/meminfo | grep -i huge
cat /sys/kernel/mm/transparent_hugepage/enabled
# 3. NUMA 메모리 정책 확인
numactl --show
cat /proc/sys/vm/numa_balancing
# 4. 메모리 배리어 관련 모듈 확인
lsmod | grep -E "kvm|vfio|iommu"
# 5. 커널 메모리 맵 확인
cat /proc/kallsyms | grep -E "vmalloc_start|vmalloc_end"
# 6. DMA 관련 정보 확인
cat /proc/dma
cat /sys/class/dma/*/in_use
# 7. 페이지 할당기 통계 확인
cat /proc/buddyinfo
cat /proc/pagetypeinfo
# 8. SLAB 통계 확인
cat /proc/slabinfo
slabtop
# 9. 메모리 압력 확인
cat /proc/pressure/memory
# 10. 커널 설정에서 아키텍처 관련 옵션 확인
# ARM64
zcat /proc/config.gz | grep ARM64
# x86_64
zcat /proc/config.gz | grep X86