30.内存存储区域

30.内存分配-内存存储区域


30.1 知识点

不同的内存存储区域

在程序运行时,系统中会有不同的内存存储区域。以下是我们目前学习到的主要存储区域:

代码段(Code Segment,或称代码存储区)

  • 用于存储函数的机器码(执行指令)等信息。
  • 通常是只读的,防止程序意外修改自己的代码。
  • 在程序加载时就被加载到内存中。
  • 生命周期较长,与程序同生共死。

数据段(Data Segment,或称数据存储区)

  • 用于存储全局变量、静态变量等信息。
  • 一般分为两个子区域:
    • 初始化数据段:存储已初始化的全局和静态变量。
    • 未初始化数据段(BSS Segment):存储未初始化的全局和静态变量,通常初始化为零。
  • 生命周期较长,与程序同生共死。

常量段(Constant Segment,或称常量存储区)

  • 用于存储字符串字面量和其他只读数据。
  • 通常是只读的,防止程序修改常量的值。
  • 比如 cout << "Hello, World" << endl 中的 "Hello, World" 就存储在常量区。
  • 生命周期由程序控制。
  • 注意:声明的常量变量不存储在常量段,而是根据其声明位置决定存储位置。

栈(Stack)

  • 用于存储局部变量、函数参数、返回值等信息。
  • 由编译器自动管理,随着函数的调用和返回而分配和释放。
  • 生命周期与函数调用相同,分配和释放速度非常快。

堆(Heap)

  • 用于存储动态分配的内存数据。
  • 需要由程序员手动管理,主动分配和释放。
  • 生命周期不固定,由程序员决定内存的分配和释放。

不同存储区域对于我们的影响

由于全局变量、静态变量、函数等内容的生命周期较长,通常不会出现因生命周期问题而找不到的情况。
然而,栈和堆上的内容由于其独特的生命周期管理,可能会给我们带来麻烦。因此,在开发中,我们需要明确区分存储在栈和堆上的内容。

栈(Stack)

  • 由编译器自动管理。
  • 程序员无需手动分配或释放内存。

堆(Heap)

  • 由程序员手动管理。
  • 需要主动分配和释放内存。

感受栈

函数中的局部变量存储在栈中,这一点可以通过指针函数的行为体现:

int* add(int a, int b)
{
    int c = a + b;   // c 是局部变量,存储在栈中
    int* p = &c;     // p 指向栈中变量 c 的地址
    return p;        // 返回指针 p
    // 函数结束后,栈内存会被释放,此时返回的内存地址将失效
}

当函数结束后,栈中的局部变量会被释放。如果外部获取函数返回的指针去访问内存地址,可能会导致不可预期的问题。


30.2 知识点代码

Lesson30_内存分配_内存存储区域.cpp

#include <iostream>
using namespace std;
int main()
{
    std::cout << "内存存储区域\n";
}

#pragma region 知识点一 不同的内存存储区域

//在程序运行时,系统中会有不同的内存存储区域
// 
//我们目前学习过的知识,涉及的存储区域有:
//1.代码段(Code Segment,或称代码存储区):
//  存储 函数的机器码(执行指令)等信息的区域
//  通常是只读的,防止程序意外修改自己的代码
//  在程序加载时就被加载到内存中
//  生命周期较长,与程序同生共死
// 
//2.数据段(Data Segment,或称数据存储区):存储 全局变量、静态变量 等信息的区域
//  一般分成两个子区域
//  初始化数据段:存储已初始化的全局和静态变量
//  未初始化数据段(BSS Segment):存储未初始化的全局和静态变量,通常初始化为零
//  生命周期较长,与程序同生共死
// 
//3.常量段(Constant Segment,或称常量存储区):存储 字符串字面量和其他只读数据 信息的区域
//  通常是只读的,以防止程序修改常量的值
//  比如 cout << "Hello, World" << endl 中的 "Hello, World" 就存储在常量区
//  生命周期由程序控制
//  注意:我们声明的常量变量不存储在常量段,而是根据在哪里声明决定存储在哪里
// 
//4.栈(Stack):存储 局部变量、函数参数、返回值 等信息的区域
//  由编译器自动管理,随着函数的调用和返回而分配和释放
//  生命周期与函数调用相同,快速分配和释放
// 
//未学习的存储区域:
//5.堆(Heap):存储 动态分配的内存数据 等信息的区域
//  由程序员手动管理,需要主动分配,主动释放
//  生命周期不固定,由程序员决定生死

#pragma endregion

#pragma region 知识点二 不同存储区域对于我们的影响

//由于 全局变量、静态变量、函数等内容
//在生命周期的角度上一般不会出现什么问题(不会出现被销毁了找不到的情况)
// 
//而会因为生命周期问题给我们带来麻烦的主要是栈和堆上存储的内容
//因此在整个开发生涯中我们需要明确区分存储在栈和堆上的内容

//栈(Stack)
//由编译器自动管理,我们无需手动管理
//堆(Heap)
//由程序员手动管理,需要主动分配,主动释放

#pragma endregion

#pragma region 知识点三 感受栈

//函数中的局部变量体现
//我们之前学习指针函数(返回值为指针的函数)充分表现了这一点
int* add(int a, int b)
{
    int c = a + b;
    int* p = &c;
    return p;
    //函数结束会被释放 如果外部获取返回的内存地址去访问可能出现问题
}

#pragma endregion

30.3 练习题

Heap 和 Stack 的区别

  • Heap 是堆:堆上的内存需要程序员手动分配和释放,程序员需要自己管理生命周期。
  • Stack 是栈:栈上的内存由系统自动管理,会在语句块执行结束时释放。例如,在函数语句块中声明的局部变量会随着函数执行结束而销毁。

全局变量和静态变量存储在什么内存区域?

  • 数据段(分为未初始化段和已初始化段)。

函数存储在什么内存区域?

  • 代码段。

局部变量存储在什么内存区域?

  • 非静态局部变量存储在栈中。
  • 静态局部变量存储在数据段。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏