栈区和堆区


之前像要用大量数据来测试各种排序算法的效率,但是在main函数内最多只能开辟几万个数的int型数组…借此我去学习了下栈和堆的知识

note:以下均是操作系统里的栈和堆,不是数据结构里面的栈和堆☯。
在这里插入图片描述

一.栈(stack)

1.栈用于函数调用时的内存分配,执行期间编译器自动分配和释放
2.函数调用用于存储:局部变量、函数参数、返回值、返回地址等

在程序的运行中,栈保存了一个函数调用所需要的维护信息,通常称为栈帧(Stack Frame),其内容如下:

  1. 函数的返回值和参数
  2. 临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量
  3. 保存的上下文:包括函数调用前后需要保持不变的寄存器
    在这里插入图片描述栈:高地址 → \rightarrow 低地址
    堆:低地址 → \rightarrow 高地址
    栈指针寄存器%esp 标记栈顶(%esp是一个32位的寄存器,里面存放着最后一个压入栈顶的项的内存地址)
    在这里插入图片描述
    1.参数反序入栈
    2.局部变量顺序入栈
    在这里插入图片描述

二.堆(heap)

1.堆需要人工malloc/new 分配内存 ,再通过free/delete释放内存。
2.堆是动态分配 (即在运行时申请内存)

静态分配:在程序编译和连接时进行内存分配
动态分配:在程序运行阶段进行的内存分配

\qquad 在进程的地址空间中,除了可执行文件、共享库和栈之外。剩余的未分配的空间都可以用来作为堆空间。
\qquad 在malloc中申请的内存,在进程结束会便不会存在。因为当进程结束后,所有与进程相关的资源,包括进程的地址空间、物理内存、打开的文件、网络链接等都被操作系统关闭或者收回、所以无论malloc申请了多少内存,进程结束后都不会存在。
\qquad malloc申请的空间:如果是指虚拟空间的话,其为连续的,即每次malloc分配后返回的空间都可以看作是一块连续的地址;如果空间是指“物理空间”则并不一定联系,对于一块连续的虚拟空间来说,其可能是由若干个不连续的物理页拼凑而成。


堆与栈的区别

  1. 申请方式:栈由系统自动分配,而堆是人工分配;
  2. 申请大小:栈获得的空间较小,而堆获得的空间较大;
  3. 申请效率:栈由系统自动分配,速度较快,而堆一般速度比较慢;
  4. 存储内容:栈在函数调用时,函数调用语句的下一条可执行语句的地址第一个进栈,然后函数的各个参数进栈,其中静态变量是不入栈的。而堆一般是在头部用一个字节存放堆的大小,堆中的具体内容是人为安排;
  5. 底层:栈是连续的空间,而堆是不连续的空间。
<think>嗯,用户之前已经问过关于Linux进程地址空间中task_structmm_struct的问题,现在他们接着问的存储类型。我需要先回顾一下之前的对话,确保这次回答的内容连贯,并且不重复之前的信息。 用户可能正在学习操作系统或内存管理的知识,特别是Linux系统的内存结构。他们可能对进程的内存布局有基本了解,现在想深入理解别。我需要解释清楚两者的存储类型,包括管理方式、分配释放、大小限制、生长方向以及存储内容等。 首先,要确认用户是否了解的基本概念,但根据之前的提问,他们已经接触过mm_struct,可能已经知道是进程地址空间的一部分。因此,我需要详细说明两者的不同之处,比如由编译器自动管理,而需要手动分配释放。还要提到数据结构,比如是LIFO结构,而更灵活。 可能需要举例说明,比如用于局部变量函数调用,用于动态分配的内存。此外,注意提到的大小限制较小,而可以更大,但受系统资源影响。生长方向方面,通常向下增长,向上,但不同系统可能不同。 还要考虑用户可能的疑惑点,比如为什么快,或者碎片问题。另外,需要提到多线程环境下每个线程有自己的,而是共享的。这部分内容可能对用户理解并发编程有帮助。 最后,确保语言通俗易懂,避免过于技术化的术语,但又要准确。可能需要使用对比表格来总结,但根据用户之前的回复,使用分段结构更合适。检查是否有遗漏的重要点,比如内存泄漏溢出的风险,这也是用户可能关心的实际问题。</think>在Linux进程的地址空间中,**(Stack)****(Heap)**是两种关键的内存域,它们的存储类型、管理方式用途有显著别。以下是它们的核心特性对比: --- ### **1. (Stack)** - **存储类型**: - **自动分配/释放**:由编译器自动管理,无需手动控制(如函数调用时压,返回时弹)。 - **连续内存**:内存空间连续分配,通过指针(`ESP`/`RSP`寄存器)快速定位。 - **LIFO结构**:后进先出(Last-In-First-Out),与函数调用返回顺序严格对应。 - **主要用途**: - 存储**局部变量**(非静态)、**函数参数**、**返回地址**等。 - 维护函数调用链的上下文(如寄存器的保存与恢复)。 - **特点**: - **固定大小**:默认大小由系统限制(如Linux中可通过`ulimit -s`查看,通常为8MB)。 - **高速度**:分配释放仅需移动指针,效率极高。 - **向下增长**:地址由高向低扩展(与相反)。 - **线程私有**:每个线程有独立的空间。 - **风险**: - **溢出**:递归过深或局部变量过大时可能耗尽空间(导致程序崩溃,如段错误)。 --- ### **2. (Heap)** - **存储类型**: - **动态分配/释放**:需手动管理(如C中的`malloc`/`free`,C++中的`new`/`delete`)。 - **非连续内存**:内存块通过链表或复杂数据结构(如红黑树)管理,可能存在碎片。 - **随机访问**:分配释放顺序无关,灵活性高。 - **主要用途**: - 存储**动态分配的数据**(如运行时确定大小的数组、对象)。 - 支持程序运行期间按需扩展内存的需求。 - **特点**: - **大小可变**:理论上受限于系统可用虚拟内存(实际受进程地址空间物理内存限制)。 - **速度较慢**:分配需搜索可用内存块,释放可能触发合并操作。 - **向上增长**:地址由低向高扩展(与相反)。 - **进程/线程共享**:同一进程的线程共享空间(需同步机制保证安全)。 - **风险**: - **内存泄漏**:忘记释放内存会导致资源耗尽。 - **碎片化**:频繁分配/释放不同大小的内存块可能产生碎片,降低利用率。 --- ### **3. 对比总结** | **特性** | **** | **** | |------------------|-----------------------------------|-----------------------------------| | **管理方式** | 编译器自动管理 | 程序员手动管理 | | **分配速度** | 极快(仅移动指针) | 较慢(需搜索可用块) | | **内存连续性** | 连续 | 可能碎片化 | | **大小限制** | 较小(默认约8MB) | 较大(受系统资源限制) | | **生命周期** | 与函数调用同步 | 显式控制(分配后需显式释放) | | **访问权限** | 仅当前函数/线程 | 全局可访问(需指针传递) | | **典型错误** | 溢出(Stack Overflow) | 内存泄漏、悬垂指针、野指针 | --- ### **4. 示例场景** - **的典型使用**: ```c void func() { int x = 10; // 局部变量() char buffer[1024]; // 上数组(需注意大小) } ``` - **的典型使用**: ```c int *arr = malloc(100 * sizeof(int)); // 分配数组 if (arr != NULL) { // 使用arr... free(arr); // 必须手动释放 } ``` --- ### **5. 关键设计思想** - **的高效性**:牺牲灵活性换取速度,适合生命周期短、大小可控的数据。 - **的灵活性**:支持动态内存需求,但需谨慎管理以避免资源问题。 - **内存隔离**:的分离设计,既保证了函数调用的安全性,又满足了动态内存的需求。 理解别,对编写高效、安全的程序(尤其是系统级或资源敏感型程序)至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值