C 内存分配

摘自网络,记录一下,稍做修改,已备温故而知新。

1

程序,代码可以被看做是一个人,人就需要有房子住,操作系统好比是政府,ZF有义务给所有人找个位置住,如果是高级人才用处大的就给你分个大又好的房子,如果你对社会没啥帮助( 没钱没本事),那你可能就需要住路边 住桥下了。

学习单片机8051 8031的时候,还没有进程,线程,操作系统的概念,程序直接下载到 rom 里面,等有了操作系统概念反过来看看会觉得以前写的单片机的代码都是单线程的。

2

C 语言内存分配的框图如下,一个正常的执行代码操作系统需要给他分配一段内存区域,这一大块内存区域还要分为几个小区域。

  1. 文本段(Text segment)
  2. 初始化数据段(Initialized data segment)
  3. 未初始化数据段(Uninitialized data segment)
  4. 堆栈(Stack)
  5. 堆 (Heap)


    图片发自简书App

3

1.文本段:

文本段,也称为代码段,是目标文件或内存中包含可执行指令的程序的一部分。

作为存储区域,文本段可以放置在堆或堆栈下方,以防止堆和堆栈溢出覆盖它。

通常,文本段是可共享的,因此对于频繁执行的程序(例如文本编辑器,C 编译器,shell 等),只需要一个副本就可以在内存中。此外,文本段通常是只读的,以防止程序意外修改其指令。
文本段可以看做 这段代码 的 大脑,需要怎么执行,做什么,都把数据保存在这个位置了。

2.初始化数据段:

初始化数据段,通常简称为数据段。数据段是程序的虚拟地址空间的一部分,其包含由程序员初始化的全局变量和静态变量。

请注意,数据段不是只读的,因为变量的值可以在运行时更改。

该段可以进一步分类为初始化的只读区域和初始化的读写区域。
例如,C 中的 char s [] =“hello world”定义的全局字符串,和 int debug = 1 之类的 C语句 将存储在初始化的读写区域中。像 const char * string =“hello world”这样的全局 C语句 会把 字符串文字“hello world”存储在初始化的只读区域中,而字符指针变量字符串存储在初始化的读写区域中。

例如:static int i = 10 将存储在数据段中,global int i = 10 也将存储在数据段中

3.未初始化的数据段:

未初始化的数据段,通常称为“bss”段,以古代汇编运算符命名,代表“由符号启动的块”。此段中的数据在程序启动之前由内核初始化为算术 0 执行

未初始化的数据从数据段的末尾开始,包含初始化为零或在源代码中没有显式初始化的所有全局变量和静态变量。

例如,变量声明为static int i; 将包含在BSS部分中。
例如,一个声明为int j的全局变量; 将包含在BSS部分中。

4.堆栈:

我们很多时候说的堆栈,实际上就是栈( stack )跟堆( heap )是没有关系的。我们学习上经常说的 压栈,说的就是压堆栈,因为堆栈有 「先进后出的原则」,所以我们操作的是栈尾。

堆栈区域传统上与堆区域相邻并向相反方向增长; 当堆栈指针遇到堆指针时,可用内存耗尽(因为理论上这个两个家伙是不可能 相遇的) 。(使用现代大地址空间和虚拟内存技术,它们几乎可以放置在任何地方,但它们通常仍会朝着相反的方向发展。)

堆栈区域包含程序堆栈,LIFO结构,通常位于存储器的较高部分。在标准的PC x86计算机体系结构上,它向零地址发展; 在其他一些架构上,它朝着相反的方向发展。“堆栈指针”寄存器跟踪堆栈的顶部; 每次将值“推”到堆栈上时都会调整它。

5.堆:

堆是通常发生动态内存分配的段。

堆区域从BSS 段的末尾开始,并从那里增长到更大的地址。堆区域由 malloc,realloc 和 free 管理,可以使用 brk 和 sbrk 系统调用来调整其大小;它们也可以使用mmap实现,将不连续的虚拟内存区域保留到进程的“虚拟地址空间”中。堆区域由进程中的所有共享库和动态加载的模块共享。

4

实用 size 命令可以分析生成的可执行程序每个段的大小,单位是(bytes 字节)。我们可以用这个命令验证上面的论证。

代码实例

#include<stdio.h>

int main()
{
    return 0;
}

Linux@dev:~/cStudygcc memory-test.c -o memory-test && size memory-test text data bss dec hex filename 1099 544 8 1651 673 memory-test Linux@dev:~/cStudy
现在代码里面什么都没有,可以看到每个段内容的大小。

#include<stdio.h>

int g;

int main()
{
    static int i;
    return 0;
}

Linux@dev:~/cStudygcc memory-test.c -o memory-test && size memory-test text data bss dec hex filename 1099 544 16 1659 67b memory-test Linux@dev:~/cStudy
我们声明了一个未初始化的全局变量和一个未初始化的静态变量后,bss 段发生了变化。

再修改一下

#include<stdio.h>

int g = 99;

int main()
{
    static int i = 100;
    return 0;
}

Linux@dev:~/cStudygcc memory-test.c -o memory-test && size memory-test text data bss dec hex filename 1099 552 8 1659 67b memory-test Linux@dev:~/cStudy
初始化后 bss 段变成原来 8 了, data 段多了 8 个字节。

再修改一下

#include<stdio.h>

int g ;

int main()
{
    static int i = 100;
    return 0;
}

Linux@dev:~/cStudygcc memory-test.c -o memory-test && size memory-test text data bss dec hex filename 1099 548 12 1659 67b memory-test Linux@dev:~/cStudy
这样 bss 段和 data 段都比初始值增加了 4 个字节。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • (JG-2014-08-20)(前半部分经过网上多篇文章对比整理)(后半部分根据ExceptionalCpp、C+...
    JasonGao阅读 5,628评论 2 23
  • 文章也同时在个人博客 http://kimihe.com/更新 引言 网络上关于内存中各区段作用的文章有很多,但不...
    QihuaZhou阅读 38,008评论 12 135
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,880评论 0 27
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,142评论 1 32
  • (编辑后转载原文出处不详)(程序中涉及所有源码CSLib) 1 进程地址空间 地址空间软件的进程运行于32位系统上...
    JasonGao阅读 1,727评论 0 1