C++ note (4)
Eiaton

数据抽象和类 Ⅲ

动态内存和类

C/C++ 内存空间分布

  • 内存分区

    memory

  1. Text–只读、共享,操作系统管理

    • 是对象文件或内存中程序的一部分,其中包含可执行指令(函数实现,库实现,字符串等资源)。文本段在堆栈的下面,是防止堆栈溢出覆盖它。

    • 通常代码段是共享的,对于经常执行的程序,只有一个副本需要存储在内存中;代码段是只读的,以防止程序以外修改指令。

  2. Initialized data

    • 通常称为数据段,是程序的虚拟地址空间的一部分,它包含程序员初始化的全局变量静态变量以及常量,可以进一步划分为只读区域读写区域
  3. Unintialized data–内核初始化为0

    • 通常称为 bss
  4. Heap–程序员管理

    • 堆是动态内存分配通常发生的部分(动态变量(对象))

    • 内存分配由低到高,分配方式类似于数据结构的链表。堆区域从BSS段的末尾开始,并从那里逐渐增加到更大的地址。

    • 堆是由程序员自己分配的,或程序结束后由操作系统自动回收。堆区域由所有共享库和进程中动态加载的模块共享。(mallocnew从堆区分配内存)

  5. Stack–编译器分配管理

    • 栈是存放自动变量,以及函数调用时保存的信息的部分(自动变量(对象)、函数参数)

    • 每当进行函数调用时,函数的实参和返回地址以及调用者的上下文环境会被存放在栈中;栈区由编译器自动分配,从高地址向低地址扩展。

    • 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

      1
      2
      char *s1 = "Literal";  // 文字在代码区,仅分配了字符指针
      // s1[0] = 'I';   // Segmentation fault
      1
      char s2[] = "Initial Literal"; // 分配数组空间
      1
      ptr_type* ptr_name = &((ptr_type){2,3}); // 分配结构空间及指针

堆 栈 的性能区别

  • 写入方面:入栈比在堆上分配内存要,因为入栈时操作系统无需分配新的空间,只需要将新数据放入栈顶即可。相比之下,在堆上分配内存则需要更多的工作,这是因为操作系统必须首先找到一块足够存放数据的内存空间,接着做一些记录为下一次分配做准备。

  • 读取方面:得益于 CPU 高速缓存,使得处理器可以减少对内存的访问,高速缓存和内存的访问速度差异在 10 倍以上!栈数据往往可以直接存储在 CPU 高速缓存中,而堆数据只能存储在内存中。访问堆上的数据比访问栈上的数据慢,因为必须先访问栈再通过栈上的指针来访问内存。

因此,处理器处理和分配在栈上数据会比在堆上的数据更加高效。

内存分区的意义

不同区域存放的数据,赋予不同的生命周期,给编程更大的灵活性。


C 动态变量(对象)管理

正确使用堆空间

  • 必须使用 #include <stdlib.h>
  • void* malloc(size_t) // 申请空间
  • void free(void*) // 释放空间
  • 申请的空间必须释放,否则会导致内存泄漏
  • free再使用或释放指针,行为不可预测。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    typedef struct { int x; int y; } Point;
    int main(void) {
    // 分配变量或一维可变数组
    Point* p1 = malloc(sizeof(Point) * 10);
      // 分配二维数组(n,m是常数)
      point (*p2)[2][3] = malloc(sizeof(Point) * 6);
      // 分配数组的数组
      int n = 2;
    int m = 3;
      Point **p3 = malloc(sizeof(Point *) * n);
      for (size_t i = 0; i < n; i++) {
      p3[i] = malloc(sizeof(Point) * m);
      }
      // do somesthing
      free(p1);
      free(p2);
      // 必须先释放行数组
      for (size_t i = 0; i < n; i++) {
    free(p3[i]);
    }
      free(p3);
      return (0);
    }

newdelete 、动态创建变量/数组、内存泄漏、 = default

C++ note (1)