【C++】C++学习笔记之九:堆、栈与内存管理

stack 栈

stack是存在于某作用域(scope)的一块内存空间(memory space)。例如当调用函数时,函数本身就会形成一个stack用来放置他所接受的参数,以及返回地址。在函数体(function body)内声明的任何变量,其所使用的内存块都取自上述的stack。

heap 堆

heap又称System heap,是指由操作系统提供的一块global内存空间。程序可动态分配(dynamic allocated)从中获得若干区块(block)

{
    Complex c1(1,2); //c1所占的空间在栈stack上
    Complex *p = new Complex(1,2);// Complex(1,2)是一个临时变量,它所占的内存空间是使用new关键字从heap堆中动态分配得来的,
                                  // 并且这块内存由指针p指向
}

栈和堆上各种对象的生命周期

stack object 栈对象的声明周期

上面例子中的C1就是stack object(存放在栈上的对象),其生命在作用与结束之际结束,这种作用域内的对象又称auto objectlocal object,因为他会被“自动清理”。

static object 静态对象的生命周期

static object(静态对象)其生命在作用域结束之后仍然存在,直到整个程序结束,其才会被“清理”。出了作用域的静态对象,虽然存在但不可见。这种变量常可以用来作为计数器,用来记录程序经过作用域的次数。如下:

int count_function(){
    static cnt = 0;//static object在被定义的时候初始化,且只初始化这一次,再次进入函数会略过此句。
    cnt++;
    return cnt;
}

global object 全局对象的生命周期

写在任何作用域之外(或称为在全局域中)的对象叫做global object(全局对象)。其生命在程序开始时开始,程序结束时结束,可以把他看作是全局域中的静态对象。

heap object 堆对象的生命周期

{
    Complex *p = new Complex(1,2);
    ……
    delete p;
}

指针p所指向的对象就是heap object(堆对象),其生命始于new,止于delete。在其作用域内只new不delete,会发生内存泄漏。如下:

{
   Complex *p = new Complex;
}

因为栈对象指针p离开作用域后就自动释放了。也就是指向堆内被分配的这块内存的指针失效了,但是这块堆上的内存仍然被标记为“已使用”。而这块内存没办法通过delete p去释放内存,将永远被占用,直至程序结束。如果这个作用域被程序多次经过,每次都会分配内存不释放,就会耗光内存,导致系统变慢,甚至程序崩溃。

new和delete

newdelete分别是在系统堆中分配和释放内存的指令,必须成对使用。除此之外还有new[] (array new)和delete[](array delete)分别是在系统堆中分配数组和释放数组的,也要成对使用。

new的编译器原理

new一个不带指针的heap object

Paste_Image.png

new一个带指针的heap object

Paste_Image.png

delete的编译器原理

delete一个不带指针的heap object

Paste_Image.png

delete一个带指针的heap object

Paste_Image.png

在VC编译器上动态分配内存的原理

cookie和补位内存块

在VC编译器中,所有动态分配的内存块的大小都是16byte的整数倍。并且都是以4byte的cookie头和4byte的cookie尾作为动态内存的起始标志。其中cookie头尾的内容一致,保存了当前动态分配的内存块的大小使用与释放与否的标记信息。
其中要求所有内存块都是16byte的整数倍是因为转换成十六进制后最后一位都为0,如64byte:0x40,16byte = 0x10。剩下最后一位为0是为了标记此块内存是正在使用(末位置1)还是已经被释放(末位置0)。
为了让分配的内存块大小是16byte的整数倍,可能会有多余的内存需要填补,VC编译器的做法是不足16整数倍字节的部分用00000000的内存块补足(4byte一条)。

debug模式

debug模式会额外再对象实际占用的内存头和尾分别加入32byte和4byte的debug信息块,而release模式则没有此信息。

动态分配内存块计算方式

debug模式下的动态内存分配的

内存块大小=cookie头尾(4byte*2)+ debug头尾(32byte+4byte)+数据实际占用空间 (n byte)+ 补位(pad byte)

release模式下的动态内存分配

release模式下只比debug少了debug信息的头尾块:
内存块大小=cookie头尾(4byte*2)+数据实际占用空间 (n byte)+ 补位(pad byte)

类对象数组的内存占用情况

动态分配类对象数组的内存占用除了上面介绍的cookie头尾,debug头尾,补位内存还会在实际占用内存中多分配4byte用来存放数组的大小(size)
内存块大小=cookie头尾(4byte2)+ debug信息头尾 + size(4byte)+数据实际占用空间(n byte) 数组size +补位(pad byte)

Paste_Image.png

下面分别用图来表示各种情况下内存占用情况:

动态分配不带pointer的单个class对象(debug模式和release模式)

debug模式

Paste_Image.png

release模式

Paste_Image.png

动态分配带pointer的单个class对象(debug模式和release模式)

Paste_Image.png

动态分配不带pointer的class对象数组(debug模式和release模式)

Paste_Image.png

动态分配带pointer的class对象数组(debug模式和release模式)

Paste_Image.png

不成对使用new[]和delete[]的潜在危机

new[] 和delete[]必须成对使用,如果使用了new[]却使用delete释放,对于不带指针的类,不会有任何影响,因为数组元素对象,会自动在作用域结束时释放;但是,对于带指针的类,就会导致只调用一次析构函数,即只有数组的第一个元素里分配的动态内存得到了释放,其他元素的动态内存则发生内存泄漏。而由cookie引领的那块内存会正常通过delete释放。也就是说,对于带指针的类对象数组,带cookie的动态内存部分不会泄漏,泄漏的是类内部通过指针指向的内存部分

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • 之前写到了关于不带有指针的class的设计思路和注意事项,但是对于C/C++语言来说,还有一个非常重要的概念就是指...
    故事狗阅读 575评论 0 1
  • Week2 Notes A.三大函数:拷贝构造,拷贝赋值,析构 string class这个不是标准库里的stri...
    古来征战几人回阅读 148评论 0 0
  • 文/鱼三 蛛丝玉缕 经过此番被暗算,悟空心里有了个疙瘩。 自己被压在这大山里,洞外就单单小玉儿一...
    鱼三123阅读 512评论 1 6
  • 使用: spring aop使用简单示例 开启单个bean的代理,ProxyFactoryBean aop失效 a...
    WY_250e阅读 206评论 0 0