C++中内存分配----C++学习之路


1.stack与heap的区别:

stack(栈): 存在于某个作用域的一块内存空间。也就是说当你调用一个函数,函数本身,也就是在这个函数的scope

中创建一块地址来存放参数,以及返回地址。离开作用域之后自动清除stack。

heap(堆):由操作系统提供的一块global内存空间,用动态分配也就是new的方式来动态获得这块,但是需要程序员自己

delete它。

stack  object生命期:离开作用域之后就auto地清理掉,自动调用析构函数。

static local object:静态声明之后,生命在作用域结束之后仍然存在,直到程序结束后才调用析构函数。

global object:全局对象,也就是说在函数之外,举个例子就是在int main()这个函数之外声明。也可以视为是一个static ob

ject对象。


heap object:举个例子更容易理解。new生成,delete销毁。

{
    complex *p = new complex(3);
.
.
.
    delete p;
}这样事正确的,如果没有delete的话会造成内存泄漏

内存泄漏:如果发生内存泄露,p这个指针离开作用域后,p已经死亡,但是p指着的那一块内存仍然存在。


2.new:先分配memory,在动用ctor(构造函数)

看看new在编译器下会发生怎样的情况:

Complex* pc=new Complex(1,2);

大部分编译器中,会先

void* mem = operator new (sizeof(Complex));内部调用malloc(n) c中分配内存

pc = static_cast<Complex*>(mem);  转型,因为void于Complex*不符,所以转型

pc->Complex::Complex(1,2); 调用构造函数。


3.delete:先调用dtor(析构函数),再释放内存。

delete ps;

在编译器中:这里以string对象的例子ps指针

String::~String(ps);字符串本身只是一个指针,字符串的析构函数是删除ps指向的动态空间

operator delete(ps); 内部调用free(ps),删除字符串本身。


4.动态分配所得的内存大小。

如果分配一个复数配置。new一个复数,首先是两个double,8个字节。

在调试模式:在内存头尾是两个4字节的cookie,在8字节上有8*4字节的内存,在8字节下有1*4字节的内存。但是每一块都要是

十六的倍数。这个时候2*4+8*4+2*4+1*4=52=64,在VC下会再填充至64.

不在调试模式:就只有上下cookie,8+*=16=16

上下cookie的作用:指示分配的内存大小,所以malloc函数约定俗成,在上下cookie标识了分配的大小。由最后一位,1或0来定义

给出去还是取回来。

另外:如果是分配一个string中,它实际上只有一个指针的大小,4字节。4+32+4+8=48 所以在cookie中的最后两位,为31,表示

48大小,1给出去。48的十六进制是30


5.构造与析构函数。arry new 与arry delete

在字符串中,是m_data = new char[strlen(cstr)+1],所对应的析构函数应该是调用delete[] m_data;而不是delete m_data;

与第四点中的知识配合,如果我们是动态分配一个数组,那么还会加上一个4字节的内存来表示由多少个元素组成。

也就是说假如Complex* p = new Complex[3];创建一个数组,三个复数,那么在VC的调试模式下内存大小如下:

8(两个cookie)+32+4 (这是调试下的debugger Header 与no man land)+8*3 (三个复数元素有六个double)+4(用于表示有几个元素)

= 72=80   cookie 为51h。

字符串的情况也一样,加入String* p = new String[3];就会有三个4字节的指针,加一个4字节的元素数以及cookie与debugger

arrynew要搭配arrydelete。不然会造成内存泄露,这种情况的内存泄露是:拿string举例子,如果是delete[] p;在第三点中有说过,delete由两个动作组成

那么arry delete会调用三次dtor,将这一整块数组删除。

但是如果使用delete p;的话,编译器不会知道你要删除的是数组,所以它不会调用三次析构函数,链接上面的例子,编译器以为下面只有一个,

只调用一次析构函数。所以它只回收了第一个指针指向的内存空间,第二个第三个指针指向的内存,就泄露,记住是指向的内存,指针的内存就不会泄露。

如果是复数,因为复数里面没有指针,所以就算复数没有些arry delete也不会造成危险。

但是养成一个好习惯,就arrynew一定对应arrydelete。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章