(C++) 详解内存地址空间

详解内存空间

0. 概述

一个C/C++ 程序,编译之后,形成的程序,在执行期间,内存中不仅存在一块区域用于存放代码,还有一些其他的区域用于使用,本节会详解C/C++内部所使用的内存地址空间,关于各内存的作用、位置做一个整体概述。

1. C++ 内存布局

操作系统的内存布局可大致分为两块:内核态和用户态,此处的内核态和用户态,不同于操作系统在执行时所进入的内核态和用户态,此处专指内存。二者有类似之处,例如:只有操作系统处于内核态时才可以访问内核态内存,因此二者容易产生混淆。

仅需了解,此处指代:内存内核态 和 内存用户态。

内存内核态暂且不去深究,内存用户态在C++程序执行时,会划分成以下内容:

【栈、堆、全局/静态区、文字常量区、程序代码区】(地址从高到低)

2. 内存分区

在这里插入图片描述

3. 栈区

栈:用于存放局部变量、函数参数、函数调用返回值、函数调用返回地址等数据,程序从main 主函数开始运行,到主函数运行结束,在此之间调用其他函数,可看作将其他函数进行压栈的一个过程,在栈区内的变量、地址等,当该函数执行结束后,其中的资源由系统自动释放。如main 函数中调用 func 函数,func 函数内生成一个数据,将其作为返回值进行返回。main 函数中使用变量进行接收,打印,可以看出打印值不同于 func 函数中的值(未定义行为),当func 返回后,该函数出栈,其中的资源被系统释放。

示例如下:

char *func() {
    char buf[] = "hello world";
    return buf;
}
int main(int argc, char *argv[]) {
    char *buf = func();
    cout << "buf = " << buf << endl;
    return 0;
}

另外值得注意的一点是,栈区的使用,操作方式类似于数据结构中的栈,即在使用时,后进先出,函数调用机制使用栈区完成,大量频繁的调用栈区,务必会造成时间资源的消耗,导致程序的执行效率下降。C 语言解决方法是使用宏代替短小频繁的函数体,C++ 语言的解决方法是使用内联函数进行替换,还需提高编程技巧。

机器在栈上申请的空间有限,因此在栈上使用的内存需要注意大小。

4. 堆区

堆位于栈区下,全局/静态区上,栈区向下生长,堆区向上生长,因此日常提到堆栈,是因为这两者的内存空间十分接近。

堆区是程序员可手动分配的内存空间,特点是需要手动申请和手动释放,在C语言中使用 malloc 和 free 进行申请和释放。C++中则使用 new 和 delete 进行申请和释放,此处不再赘述 malloc/free 和 new/delete 的区别,若感兴趣请自行查询相关资料。

堆区申请的数据在程序执行阶段不会被系统所自动释放,因此C和C++程序员需要注意内存大小,内存释放问题。(程序结束时会被操作系统回收)

需要注意:

1.申请堆内存之后,立刻验证内存空间是否申请成功。

2.申请行为必须对应释放行为,有申请内存,则必有释放行为,因此写 malloc 之后立刻写上free语句。new/delete 同理。

3.free 和 delete 虽然传入的是指针,但释放的确是内存空间,因此需要将该指针置为null,防止野指针问题。

另外,堆的运行速度、效率不及栈,且存在内存碎片问题。 使用 malloc 和 free 时,需要添加头文件。

5. 全局/静态区

全局区、静态区是一片区域,原因在于全局变量和静态变量的内存地址都位于这片空间下。该空间位于堆下,低地址。

定义一个变量时,需要及时进行初始化,变量被定义 static 之后,只有当前模块可见。当一个局部变量被定义为 static时,虽然该局部变量的可见范围仍然属于该函数,但该局部变量的生命周期已经延长到了程序生存期。

6. 文字常量区(只读)

文字常量区用于定义常量字符串,程序结束后由系统进行释放,不可进行写操作。

const char* 定义文字常量后,直接使用字符串,二者处于的地址相同,都位于文字常量区。

#include <func.h>

#include <iostream>
using std::cout;
using std::endl;

int main(int argc, char *argv[]) {
    const char *str = "Hello world";
    printf("str address = %p\n", str);
    printf("hw  address = %p\n",&"Hello world");
    return 0;
    // str address = 0x561f4d567004
	// hw  address = 0x561f4d567004
}

局部的常量字符串放在栈或者文字常量区,视编译器而定。

7. 程序代码区(只读)

顾名思义,存放程序代码的位置,函数也是存放在某个内存地址的,比如,可以打印看一下main函数的运行地址。

#include <iostream>
using std::cout;
using std::endl;

int main(int argc, char *argv[]) {
    printf("main address =  %p\n", &main);
    return 0;
}

参考:https://www.cnblogs.com/songdanzju/p/7422507.html

相关推荐

  1. C++命名空间详解

    2024-02-22 06:00:04       45 阅读
  2. 深入学习Linux内核 - 进程地址空间

    2024-02-22 06:00:04       32 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-22 06:00:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-22 06:00:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-02-22 06:00:04       82 阅读
  4. Python语言-面向对象

    2024-02-22 06:00:04       91 阅读

热门阅读

  1. 单例模式的介绍

    2024-02-22 06:00:04       54 阅读
  2. 利用电商数据API接口上货、铺货

    2024-02-22 06:00:04       57 阅读
  3. 设计模式浅析(五) ·单例模式

    2024-02-22 06:00:04       52 阅读
  4. Python编程语言学习

    2024-02-22 06:00:04       40 阅读
  5. C++基本格式

    2024-02-22 06:00:04       46 阅读
  6. 网安初探-春秋云镜

    2024-02-22 06:00:04       49 阅读
  7. Vue常用指令+用法举例 详解

    2024-02-22 06:00:04       58 阅读
  8. SEO优化对服务器有影响

    2024-02-22 06:00:04       50 阅读
  9. 时序电路的Verilog设计——基本时序元件

    2024-02-22 06:00:04       42 阅读
  10. 算法刷题day15

    2024-02-22 06:00:04       60 阅读
  11. 【C++】每周一题——1024.2.21

    2024-02-22 06:00:04       51 阅读