1. 定义和用途
-
栈(Stack):
- 栈是静态分配的内存区域,大小在程序运行时由编译器确定。在 Linux 内核中,栈的内存是通过固定大小的连续内存块分配的,并且遵循“后进先出”的规则。这意味着栈中的内存是按顺序压入和弹出的,通常用于局部变量、函数调用信息(如返回地址、参数、局部变量等)。
-
堆(Heap):
- 堆是动态分配的内存区域,大小可以在程序运行时通过系统调用(如
malloc
或kmalloc
)动态请求。在 Linux 内核中,堆是通过内存管理子系统动态分配的,主要用于需要动态内存分配的场景。堆的分配方式相对复杂,涉及内存管理算法,如伙伴系统(buddy system)、slab 分配器等。
- 堆是动态分配的内存区域,大小可以在程序运行时通过系统调用(如
2. 内存布局
在 Linux 系统中,进程的内存布局通常分为多个区域,其中主要包括:
- 栈: 位于每个线程的用户空间内存的顶部,通常从高地址向低地址扩展。
- 堆: 位于已分配静态数据(如全局变量、代码段、数据段、BSS 段等)之后,通常从低地址向高地址扩展。
内存布局大致如下:
+------------------+ 高地址
| 栈 (Stack) |
| ... |
| |
| 动态库 (Shared Libraries) |
| 堆 (Heap) |
| |
| ... |
| BSS 段 (未初始化数据) |
| 数据段 (已初始化数据) |
| 代码段 (Text Segment) |
+------------------+ 低地址
3. 分配与管理
- 栈的分配与管理:
- 栈的管理由内核通过 CPU 寄存器和栈帧结构进行自动控制,当函数调用时,系统会为该函数分配相应的栈空间。
- 栈内存的分配和释放是由编译器和操作系统自动管理的。当函数被调用时,栈帧(Stack Frame)会自动分配,当函数返回时,栈帧自动释放。因此,栈内存的分配速度非常快,且不会导致内存碎片。
- 栈的大小通常是有限的,并且在程序启动时由操作系统设定。在 Linux 系统中,栈的大小可以通过
ulimit -s
命令查看和设置。
- 堆的分配与管理:
- 堆的分配和管理主要依赖于内核的内存分配机制。Linux 内核通过页帧分配器(page frame allocator)和 slab 分配器管理堆内存
- 堆内存的分配和释放是由程序员通过系统调用显式控制的。在 Linux 中,动态内存分配通常使用
brk
或mmap
系统调用实现。 - 堆内存的分配灵活,但由于需要手动管理内存,可能会导致内存泄漏或碎片问题。此外,堆内存分配速度通常比栈慢,因为需要操作系统的参与。
4. Linux 内核中的实现
-
栈在内核中的实现:
- 栈通常是通过进程控制块(
task_struct
)中的thread_info
结构体来管理的。在 Linux 中,每个进程或线程的栈通常位于一个固定大小的内存块中,内核使用thread_info
中的栈指针来跟踪栈的顶部。 - 栈的大小是固定的,通常在内核编译时或进程创建时设置,并且栈的扩展是向下进行的。
- 栈通常是通过进程控制块(
-
堆在内核中的实现:
- 堆内存的管理主要依赖于
brk
和mmap
系统调用。brk
用于调整进程的堆顶指针,通常用于小的、连续内存分配。而mmap
则用于大块内存的分配,并将内存映射到虚拟地址空间。 - 内核通过
mm_struct
结构体管理进程的内存区域,其中堆的起始和结束地址由brk
字段标识。通过mmap
分配的内存区域则通过虚拟内存区域(vm_area_struct
)链表管理。
- 堆内存的管理主要依赖于
推荐学习 https://xxetb.xetslk.com/s/p5Ibb