【C/C++值班室】,程序运行时的内存使用(一)(大家来拍砖啊)

北极猩猩 2004-07-10 11:44:09
【C/C++值班室】,程序运行时的内存使用(一)

计算机程序运行时需要保存和处理数据,而所有的运行时使用的数据都是保存在内存当中的。下面我们就来看一看程序在运行时是如何使用内存的。

一个程序中使用的内存都是通过变量来访问的(可能是直接访问,也可能是间接访问),我们看看一个程序中都有哪些种类的变量,它决定着程序运行时的内存使用方式。

类型一:全局变量、静态变量、静态成员变量和静态局部变量
这些变量的特点是它们从程序运行的一开始就存在着,可以在程序运行过程中的任意时刻,从任意的位置进行访问,它们将一直生存到程序结束时为止。
这一类变量是在一块固定的全局内存区(或称为静态内存区)中分配的,这块空间由程序在开始运行时保留,保存在这一空间中的变量也在运行开始是创建并初始化。所有这些变量都一直保存在这块区域中,并在整个程序的运行过程中都是存在的。因此,程序可以随时访问。

类型二:局部变量
局部变量指那些在函数中声明和使用的变量,它们伴随着函数的执行而生,伴随着函数的返回而死,它们的生存历程就是所在函数的执行过程。它们只能在所在的函数中访问,在函数之外没有意义。它们的特点是,生存时间是完全确定的,生命周期由函数调用机制处理。
这类变量通常在一块称为栈(stack)的内存空间中分配。stack所需要的空间通常是在程序运行开始是预先分配的,但是,占空间的使用并不是固定的。在我们调用一个函数时,程序会为我们在栈上面分配一块这个函数需要的内存空间,这块空间称为栈帧(stack frame),被调函数所需要的所有局部变量都在函数开始执行之前在这块空间上创建,在函数执行结束时,栈帧将被撤销,函数中的局部变量就不再存在了。(所以,如果函数返回一个执行局部变量的指针,该指针指向的内存在被访问时会出现非法内存访问错误)栈中的数据可以在当前函数和所有被当前函数调用的函数中使用,因为在函数调用其他函数时不会撤销自己的栈帧,而是在自身栈帧之上创建为被调函数创建一个新的栈帧。
要注意,程序预先分配的栈空间是有限的(这个值可以在编译时确定),因此,程序的函数调用就不会是无止境的,如果函数调用过深,或者函数局部变量过多(比如:int a[100000000000000] :P)将会导致程序耗尽栈内空间而报错(stack overflow)。

类型三:动态分配的内存
动态分配的内存是指那些用malloc(realloc,...)和new、new[]分配的内存,它们在程序中是不能够直接访问的,必须通过指针,用*p或者p[10]再或者p->i的方式间接访问,而它们的释放必须由程序员通过free或delete、delete[]主动进行(除非你的语言的runtime可以向java那样自动进行内存回收),它们的生存周期可以由程序员随心所欲的控制,要长即长,说短就短。不过也可能由于程序员忘记回收而使无用的数据一直占据着内存。
这类变量在另一块内存中分配,这块内存称为堆(heap)。堆中的内存可以根据实际需要在程序的运行过程中分配(malloc/new)和释放(free/delete),在堆中分配的数据将一直存在下去,直到明确地被释放或者保存到程序运行结束时。堆中的内存被释放之前它可以在程序中任意访问,并被所有函数共享访问(注意和战中变量的区别)。堆中内存的分配通常是由操作系统的API进行的(比如windows中的GlobalAlloc等),而C/C++中使用malloc和new来调用API进行内存分配。
动态内存分配永远是同指针联系在一起的,因为对中分配的内存不能直接在程序中访问,必须通过指针变量进行间接访问。对堆中内存的分配操作将会返回分配好的内存的一个指针,我们通过这个值针对分配的空间进行操作。指针是一个变量,它保存着一个内存地址,使我们可以根据这个地址访问这个地址单元上所保存的数据。


程序对内存的动态分配能力是程序设计灵活性的一个象征(要知道,最早的高级语言入Fortan是不能动态分配内存的)。而对于是用指针通过手动内存管理的C/C++来说,灵活意味着风险。指针的使用可能会缠身很多错误,现在让我们一一道来。
1,非法访问
指针中保存一块内存单元的地址,可是它却不能保证这块地址一定是我们可以访问的。这块地址可能是一块不属于你的内存,如果,你强行访问那么轻则产生保护性错误,使你的程序崩溃;重则破坏系统的数据结构是操作系统崩溃。

2,访问越界
我们可以使用指针分配一整块内存供程序使用,可以程序并不会监督你的访问范围是不是超出了你分配的大小,一切都要你自己负责。比如:
char * s= new char[100];
*(s+100) = 'h'; //Boom!!!!!

3,内存泄漏
我们一旦在堆中分配了内存他就会一直存在,直到我们释放。而如果我们由于某种原因,在释放之前就失去了对所分配的内存的指针,那么这块内存将变成一只断了线的风筝,永远占据着内存空间。而如果这种丢失经常而且持续性的发生,我们的程序就会像漏水的桶一样,最终让无用数据耗光所有的内存空间。下面给出一个例子,看看大家能不能知道内存是怎样溜掉的。

bool m() {
try{
Something * s=new Something();
//do something...
delete s;
}
catch(int errCode) {
return false;
}
return true;
}

4,错误释放
和内存泄漏相对,太过积极的释放内存也会产生错误。首先,不是任意的内存都是可以释放的,必须要保证指针指向的是由malloc/new分配的内存,而且指向的分配到的内存的开始位置,否则结果就和非法访问一样。同样,对已经是放过的内存再次调用free和delete也不会得到什么好下场。
由于,C++中规定delete 0不会产生任何错误,所以,在每次调用delete之后将指针设为0是一个不错的习惯,值得发扬。



本文简单介绍了应用程序中对内存分配和使用的知识。在后边的文章里我们将继续讨论,内存分配对程序设计带来的影响,欢迎大家拍砖(最好用金砖)

【C/C++值班室|北极星|2004.7.10】
...全文
1095 46 打赏 收藏 转发到动态 举报
写回复
用AI写文章
46 条回复
切换为时间正序
请发表友善的回复…
发表回复
yangfasheng 2004-11-03
  • 打赏
  • 举报
回复
MARK
beyondtkl 2004-07-13
  • 打赏
  • 举报
回复
mk
真的李小龙 2004-07-12
  • 打赏
  • 举报
回复
楼不在高,有仙则灵。
不就是写‘程序开发人员’的恶作句。
要想搞懂:抛弃WINDOWS
用LINUX。不过要先看他的原代码哦!
我真准备看:我机子上有!
howler 2004-07-12
  • 打赏
  • 举报
回复
mark
BluntBlade 2004-07-12
  • 打赏
  • 举报
回复
我写的专题没人理……
:....(
hxygx 2004-07-12
  • 打赏
  • 举报
回复
好标记
niky8053 2004-07-12
  • 打赏
  • 举报
回复
非常感谢,C/C++值班室
lbaby 2004-07-11
  • 打赏
  • 举报
回复
!@@#!@$(&$%(^$~
没砖了,你等着啊~~
aixuer 2004-07-11
  • 打赏
  • 举报
回复
mark & up
oldjackyone 2004-07-11
  • 打赏
  • 举报
回复
估计是废人干的,嘿嘿~~
  • 打赏
  • 举报
回复
呵,不是我干的:)
北极猩猩 2004-07-11
  • 打赏
  • 举报
回复
居然被置顶了,头一回享受这么高的荣誉
北极猩猩 2004-07-11
  • 打赏
  • 举报
回复
再顶一顶,快来人看啊。
haha52 2004-07-11
  • 打赏
  • 举报
回复
UP
Wolf0403 2004-07-11
  • 打赏
  • 举报
回复
http://community.csdn.net/Expert/TopicView1.asp?id=3162763

狗狗的问题我没法解答,希望北极星兄台能指点迷津
Jinhao 2004-07-10
  • 打赏
  • 举报
回复
不错,辛苦了,我顶
期待后边地
freefalcon 2004-07-10
  • 打赏
  • 举报
回复
up,不错,辛苦了
补充一点,全局变量的初始化顺序是不被编译器所保证的
北极猩猩 2004-07-10
  • 打赏
  • 举报
回复
yesdo(小兵)
呵呵,那本书我没看过。

这是本人系列文章的第一部分,后边还有哦
peter9606 2004-07-10
  • 打赏
  • 举报
回复
期待着 二 的早日面世 ;)
peter9606 2004-07-10
  • 打赏
  • 举报
回复
4,错误释放
和内存泄漏相对,太过积极的释放内存也会产生错误。首先,不是任意的内存都是可以释放的,必须要保证指针指向的是由malloc/new分配的内存,而且指向的分配到的内存的开始位置,否则结果就和非法访问一样。同样,对已经是放过的内存再次调用free和delete也不会得到什么好下场。
由于,C++中规定delete 0不会产生任何错误,所以,在每次调用delete之后将指针设为0是一个不错的习惯,值得发扬。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~学习
加载更多回复(25)
1、这是一个C/C++新手基础教程,合适完全不懂程序的新手入坑,半生不熟的程序入坑,其他语言的程序想学C++。2、这是一个C++基础系列教程,本季是作为基础教程的第一集,主要为学习C语言,为学好C++打好坚实的基础,C++包含了C部分,要学好C++,学好C语言是必然的趋势。3、C++入行系列教程是一个由浅入深的一个过程,第一第二集主要学习C语言和C++,后面三集主要教大家如何用C++去写封装一些商业级案例,。第三集主要学SOCKET编程,了解熟悉socket编程。第四集主要学用C++自定义数据库,纯C++编写 第五集主要学习数据结构,学习C++的各个标准模板库。大家如有兴趣可以学习已经制作完毕的C++游戏服务器和Mysql数据库教程。4、C++入行系列教程不单单是讲解语法知识,还有另外讲解C/C++内存,以及内存优化,工作中经常用到的经验,以及避免一些坑。5、本季教程主要内容是讲解编程语言,计算机组成原理,开发环境,C语言基础语法。普及一些基础知识,并且结合工作经验讲解一些案列。教程后面会安排一些工作任务给学员。具体内容看教程课题大纲6、不保证每个人都学的会,良心之作,不喜勿买。7、教程会结合本人20年工作经验讲解工作经常用到的地方,以及新手入职面试需要注意的地方。打好基础学好C++走遍天下都不怕,相信自己,你行的。8、每一集都是单独的,需要单独购买噢,亲,请看清楚,C++系列每一集 并不是必须购买的。新手朋友第一第二集是必须学购买的哈,千万记得。切记切记切记

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧