C++程序的内存分区

在 C++ 中,内存主要被划分为全局区、堆区、栈区、常量区和代码区,每个区域都有其特定的用途和特点。

分区名称作用特点示例
全局区存放全局变量和静态变量程序运行期间一直存在,在程序结束时由系统释放内存。全局变量和静态变量的生命周期从程序开始到程序结束。int globalVar = 10;
static int staticVar = 20;
堆区由程序员手动分配和释放内存,用于动态内存分配内存分配灵活,但需要程序员手动管理内存,若忘记释放可能导致内存泄漏。int* ptr = new int(5);
delete ptr;
栈区存放函数的参数、局部变量等由编译器自动分配和释放,具有先进后出的特点。函数调用结束后,栈上的内存自动被释放。void function() { int localVar = 3; }
常量区存放常量数据,如字符串常量、const 修饰的常量等常量区的内容在程序运行期间不可修改,多个相同的常量在常量区中可能只存储一份。const int constVar = 100;
char* str = “Hello World”;
代码区存放程序的可执行代码通常是只读的,用于存储 CPU 执行的机器指令。代码区的大小在程序编译时就已经确定。程序中的函数体、类的成员函数等代码都存放在代码区。

1. 全局区(静态区)

知识点

  • 存储内容:全局变量和静态变量存放在此区域。全局变量是在函数外部定义的变量,而静态变量是使用 static 关键字修饰的变量,可以是全局静态变量或局部静态变量。
  • 生命周期:从程序开始运行到程序结束,全局区的变量一直存在,不会因为函数的调用或返回而销毁。
  • 初始化情况:未初始化的全局变量和静态变量存放在全局区的未初始化段(BSS 段),初始化为 0;已初始化的全局变量和静态变量存放在全局区的已初始化段。

示例代码

#include <iostream>
// 全局变量
int globalVar; 
// 未初始化的全局变量,存放在 BSS 段
int initializedGlobalVar = 10; 
// 已初始化的全局变量,存放在已初始化段
void func() {
    // 局部静态变量
    static int staticVar; 
    // 未初始化的局部静态变量,存放在 BSS 段
    static int initializedStaticVar = 20; 
    // 已初始化的局部静态变量,存放在已初始化段
}
int main() {
    func();
    return 0;
}

注意事项

  • 全局变量和静态变量的作用域不同,但都存储在全局区。全局变量的作用域是整个程序,而局部静态变量的作用域仅限于定义它的函数内部。
  • 过多使用全局变量会增加程序的耦合性,降低代码的可维护性和可测试性,应尽量避免不必要的全局变量。

2. 堆区

知识点

  • 存储内容:通过 new 运算符动态分配的内存块存放在堆区。堆区的内存分配和释放由程序员手动控制。
  • 生命周期:由程序员控制,使用 new 分配的内存,必须使用 delete(对于单个对象)或 delete[](对于数组)来释放,否则会导致内存泄漏。
  • 分配方式:堆区的内存分配是动态的,分配和释放的时间和顺序可以不固定。

示例代码

#include <iostream>
int main() {
    // 动态分配一个整数
    int* ptr = new int(5);    
    std::cout << *ptr << std::endl;
    // 释放内存
    delete ptr; 

    // 动态分配一个整数数组
    int* arr = new int[10]; 
    // 释放数组内存
    delete[] arr; 

    return 0;
}

注意事项

  • 必须确保每次使用 new 分配的内存都有对应的 delete 或 delete[] 操作,避免内存泄漏。
  • 堆区的内存分配和释放可能会导致内存碎片问题,影响内存的使用效率。
  • 对已经释放的内存再次进行 delete 操作会导致未定义行为,应该避免。

3. 栈区

知识点

  • 存储内容:函数的局部变量、函数参数、返回地址等存放在栈区。栈区的内存分配和释放由编译器自动完成。
  • 生命周期:与函数的调用和返回相关。当函数被调用时,会在栈上为局部变量和函数参数分配内存;当函数返回时,这些内存会自动释放。
  • 分配方式:栈区的内存分配和释放是按照后进先出(LIFO)的原则进行的,类似于栈数据结构。

示例代码

#include <iostream>
void func(int param) {
    // 局部变量
    int localVar = 20;    
    std::cout << param << " " << localVar << std::endl;
}
int main() {
    int arg = 10;
    func(arg);
    return 0;
}

注意事项

  • 栈区的空间有限,如果递归调用过深或局部变量占用空间过大,可能会导致栈溢出错误。
  • 不要返回局部变量的引用或指针,因为局部变量在函数返回后会被销毁,返回的引用或指针将指向无效的内存地址。

4. 常量区

知识点

  • 存储内容:存放常量字符串和使用 const 修饰的全局常量。常量区的内容在程序运行期间不可修改。
  • 生命周期:从程序开始运行到程序结束,常量区的内容一直存在。

示例代码

#include <iostream>
// 常量字符串
const char* str = "Hello, World!"; 

// 全局常量
const int constantValue = 100; 

int main() {
    std::cout << str << " " << constantValue << std::endl;
    return 0;
}

注意事项

  • 尝试修改常量区的内容会导致未定义行为,应该避免对常量进行修改操作。
  • 不同编译器对常量区的实现可能有所不同,但都保证常量的不可修改性。

5. 代码区

知识点

  • 存储内容:存放程序的可执行代码,即编译后的机器指令。代码区是只读的,防止程序在运行过程中被意外修改。
  • 生命周期:从程序开始运行到程序结束,代码区的内容一直存在。

注意事项

  • 代码区的内容由编译器生成,一般不需要程序员手动管理。
  • 由于代码区是只读的,任何尝试修改代码区内容的操作都会导致未定义行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值