C语言的内存管理

作者: shad0w_walker(admin) 分类: 基础知识 发布时间: 2017-04-07 00:10 ė 6 没有评论

对于一个C语言的程序,其内存由代码段、数据段、BSS段、堆、栈构成。

代码段:用于存放函数体的二进制代码,属于静态内存分配。

数据段:有人称之为全局已初始化读写数据段。存放已初始化的全局变量以及静态变量,属于静态内存分配。分为读写和只读两个部分,字符串常量就是存放在只读数据段内。

BSS段:有人称之为全局未初始化读写数据段。存放未初始化的全局变量以及静态变量,属于静态内存分配。我们在使用全局变量时会发现,即使没有手动初始化,变量也会被自动初始化填充0,但这是隐式初始化,不是未初始化。我理解的是,全局未初始化变量会在使用前被初始化填充0,但如果未被使用,就不必初始化,记录在BSS段内。所以说BBS段是不存放数据的。

:由程序员分配和释放的内存空间,即使用malloc、free等函数操作,属于动态内存分配。(C++中有new/delete)

:由编译器自动分配和释放,存放函数的参数、局部变量的值,即我们写在{}内的变量,有动态和静态分配两种方式。

 

栈是一个后进先出的结构,每个线程都会被分配一个栈,函数在调用时,会把传参压入栈中,函数执行完毕后返回值也会放入栈中。如果学过汇编一定对系统中的栈不会陌生,汇编中有push和pop等指令操作栈,在call调用函数前要用push将函数传参压入栈中,调用完毕使用pop释放空间。理解了这一点也就能理解为什么栈用于存放局部变量,并且由编译器管理。

栈是一个很高效的内存管理机制,使用也非常频繁,因为变量与变量之间无缝连接,但支持的变量类型有限,栈中一般只存放整形、浮点、字符串、指针等系统支持的简单数据类型。需要注意的是,栈是向下生长的,所以栈的空间有限,linux中一般是8M,但也可以根据情况将栈空间开大。

根据栈的空间有限这一点就能够理解以下两个内存溢出状况:1、局部变量过大,因为栈不下这么多值;2、递归函数调用层数过多,因为一直调用函数而没有结束调用,栈内压不了大量的传入参数。

 

堆不是由系统支持的,而是由malloc/free等库函数支持的一套结构。当需要分配内存时,首先到堆内寻找空闲的空间,如果堆内空间不够,则会通过系统调用增加程序数据段的大小,以增加堆的大小。当需要释放内存时,会在堆内释放空间,然后通过一些手段处理空闲空间,例如将小空闲空间合并为大空闲空间。

堆向上生长,是一个操作灵活方便,支持各种数据类型的内存管理机制,但是堆在操作时涉及到系统调用、寻找空闲空间等,效率没有栈来得高。

为什么不直接使用系统调用而要用堆呢?有如下理由:1、系统调用申请的内存都是以固定大小或其倍数分配的,例如以页为单位,这样会造成内存的浪费;2、系统调用的开销大。

 

看下面一段代码,体会C语言的内存布局

需要注意两点:

1、char *s2 = “12345”是将常量字符串分配到了数据段,数据段是静态分配,是不能修改的,所以s2[0]=’2’这样的操作是会出错的。

2、s3分配了堆和栈两部分的空间,指针存在栈中,malloc的空间存在堆中

 

本文出自shad0w_walker,转载时请注明出处及相应链接。

本文永久链接: https://www.sdwalker.com/archives/718.html

0

发表评论

电子邮件地址不会被公开。 必填项已用*标注

返回顶部