您的位置:首页 > 编程语言 > C语言/C++

C/C++内存分配

2016-03-17 19:29 417 查看
一个有C/C++编译的程序占用的内存分为以下几个区域:

1.栈区(stack)

由系统自动分配和释放,用于存放函数的参数值,局部变量值等。其在内存中是一块连续的存储区域,由底地址向高地址延伸。栈的大小可以在编译器中设定Linker->System下。也可以在代码中指定#pragma comment(linker, "/STACK:4096")用代码设置,/STACK后面数字为容量。默认的栈大小是1M。

2.堆区(heap)

由new分配内存块,他们的释放由应用程序去控制,一般一个new就要对应一个delete。如果程序没有释放掉,那么在程序结束后,操作系统会自动回收。堆可以动态地拓展和收缩。堆的大小受限于计算机系统中有效的虚拟内存。

3.全局/静态区(static)

全局变量和静态变量被分配到同一块内存中,在以前的 C 语言中,全局变量又分为初始化的和未初始化的(初始化的全局变量和静态变量在一块区域,未初始化的全局变量与静态变量在相邻的另一块区域,同时未被初始化的对象存储区可以通过 void* 来访问和操纵,程序结束后由系统自行释放),在 C++ 里面没有这个区分了,他们共同占用同一块内存区。

4.常量存储区

比较特殊的存储区,存放的是常量,不允许修改。

函数的变量在内存中的地址:

#include <stdio.h>

void TestAddress(int a, int b, int c)
{
int* d = new int[10];
int* e = new int[20];

printf("a=%0x;\nb=%0x;\nc=%0x;\nd=%0x;\ne=%0x;\n", &a, &b, &c, &d, &e);
}

int main()
{
TestAddress(1, 2, 3);
printf("TestAddress:=%x", &TestAddress);
}


运行结果:



我们发现,函数参数的地址是递增的,局部变量的地址是递减的(分配在堆上)。当使用char,short,int时候地址增量为4,当使用double时地址增量为8,当使用引用时参数的地址与被引用对象的地址一致,如果内用的是是一个指针,那引用参数的地址与指针内存地址一致。对于new的内存,地址增量为12,对于double和int都一样。

再来看下如果局部变量分配在栈上会怎么样?

#include <stdio.h>

void TestAddress(int a, int b, int c)
{
int d;
int e;

printf("a=%0x;\nb=%0x;\nc=%0x;\nd=%0x;\ne=%0x;\n", &a, &b, &c, &d, &e);
}

int main()
{
TestAddress(1, 2, 3);
printf("TestAddress:=%x", &TestAddress);

}



对于局部变量在栈上的地址,int型增量是12,double型增量是16。

以上结果使用win7 64位操作系统 vs2013 Win32程序

内存字节对齐:

为什么要进行字节对齐:效率。计算机从内存中取数据是按照一个固定长度的。以32位机为例,它每次取32位也就是4个字节。以int为例,如果它在内存中存放的位置按5字节对齐,也就是说1个int的数据全部落在计算机一次区数据的区间内,那么只需要取一次就可以了。如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,这样效率就降低了。内存对齐是典型的以空间换效率的方法。

结构体内成员按自身长度进行对齐。当未明确指定时,以结构体中最长的成员长度为齐有效值。当用#pragma pack(n)指定时,以n和结构体中最长的成员的长度中较小者为齐对齐。当用__attribute__ ((__pack__))指定长度时,强制按照此值为结构体的有效对齐值。

#include <stdio.h>

#pragma pack (1)

class A
{
char a;
int b;
char c;
short d;
};

class B
{
char a;
char b;
short d;
int c;
};

int main()
{
int a = sizeof(A);
int b = sizeof(B);

int i = 0;
}

#pragma pack (1) a=8 b=8
#pragma pack (2) a=10 b=8
#pragma pack (4) a=12 b=8
可见在对齐方式不同的情况下,定义相同个数变量与类型的两个类,在定义顺序不同的情况下内存占用情况也不同。

空类内存大小为1字节

继承时候内存占用:

普通继承

#include <stdio.h>

#pragma pack (4)

class Father
{
public:
Father()
{

}

~Father()
{

}

int a;
};

class Son : public Father
{
public:
Son()
{

}

~Son()
{

}

int b;
};

int main()
{
int father = sizeof(Father);
int son = sizeof(Son);
}
father = 4;

son = 8;

继承有成员函数

#include <stdio.h>

#pragma pack (4)

class Father
{
public:
Father()
{

}

~Father()
{

}

void Test();

int a;
};

void Father::Test()
{

}

class Son : public Father
{
public:
Son()
{

}

~Son()
{

}

int b;
};

int main()
{
int father = sizeof(Father);
int son = sizeof(Son);
}

father = 4;

son = 8;

继承有虚函数

#include <stdio.h>

#pragma pack (4)

class Father
{
public:
Father()
{

}

~Father()
{

}

virtual void Test();

int a;
};

void Father::Test()
{

}

class Son : public Father
{
public:
Son()
{

}

~Son()
{

}

int b;
};

int main()
{
int father = sizeof(Father);
int son = sizeof(Son);
}

father = 8;

son = 12;

继承基类与派生类都有虚函数

#include <stdio.h>

#pragma pack (4)

class Father
{
public:
Father()
{

}

~Father()
{

}

virtual void Test();

int a;
};

void Father::Test()
{

}

class Son : public Father
{
public:
Son()
{

}

~Son()
{

}

virtual void Test1();

int b;
};

void Son::Test1()
{

}

int main()
{
int father = sizeof(Father);
int son = sizeof(Son);
}

father = 8;

son = 12;

多继承

#include <stdio.h>

#pragma pack (4)

class Father
{
public:
Father()
{

}

~Father()
{

}

virtual void Test();

int a;
};

void Father::Test()
{

}

class Mother
{
public:
Mother()
{

}

~Mother()
{

}

virtual void TestM();
};

void Mother::TestM()
{

}

class Son : public Father, public Mother
{
public:
Son()
{

}

~Son()
{

}

virtual void Test1();
};

void Son::Test1()
{

}

int main()
{
int father = sizeof(Father);
int son = sizeof(Son);
}

father = 8;

son = 12;

mother = 4;

多继承

#include <stdio.h>

#pragma pack (4)

class Base
{
public:
Base(){}
~Base(){}

virtual void TestBase();

int t;
};

void Base::TestBase()
{

}

class Father : public Base
{
public:
Father()
{

}

~Father()
{

}

virtual void Test();

int a;
};

void Father::Test()
{

}

class Mother : public Base
{
public:
Mother()
{

}

~Mother()
{

}

virtual void TestM();
};

void Mother::TestM()
{

}

class Son : public Father, public Mother
{
public:
Son()
{

}

~Son()
{

}

virtual void Test1();
};

void Son::Test1()
{

}

int main()
{
int father = sizeof(Father);
int mother = sizeof(Mother);
int son = sizeof(Son);
}

father = 12;

son = 20;

mother = 8;

虚继承

#include <stdio.h>

#pragma pack (4)

class Base
{
public:
Base(){}
virtual ~Base(){}

virtual void TestBase();

int t;
};

void Base::TestBase()
{

}

class Father : public virtual Base
{
public:
Father()
{

}

virtual ~Father()
{

}

virtual void Test();

int a;
};

void Father::Test()
{

}

class Mother : public virtual Base
{
public:
Mother()
{

}

virtual ~Mother()
{

}

virtual void TestM();
};

void Mother::TestM()
{

}

class Son : public Father, public Mother
{
public:
Son()
{

}

virtual ~Son()
{

}

virtual void Test1();
};

void Son::Test1()
{

}

int main()
{
int base = sizeof(Base);
int father = sizeof(Father);
int mother = sizeof(Mother);
int son = sizeof(Son);
}
father = 20;

son = 28;

mother = 16;

base = 8;

虚继承

#include <stdio.h>

#pragma pack (4)

class Base
{
public:
Base(){}
virtual ~Base(){}

virtual void TestBase();

int t;
int t1;
int t2;
int t3;
int t4;
int t5;
int t6;
int t7;
int t8;
};

void Base::TestBase()
{

}

class Father : public virtual Base
{
public:
Father()
{

}

virtual ~Father()
{

}

virtual void Test();

int a;
};

void Father::Test()
{

}

class Mother : public virtual Base
{
public:
Mother()
{

}

virtual ~Mother()
{

}

virtual void TestM();
};

void Mother::TestM()
{

}

class Son : public Father, public Mother
{
public:
Son()
{

}

virtual ~Son()
{

}

virtual void Test1();
};

void Son::Test1()
{

}

int main()
{
int base = sizeof(Base);
int father = sizeof(Father);
int mother = sizeof(Mother);
int son = sizeof(Son);
}

father = 52;

son = 60;

mother = 48;

base = 40;

不用虚继承

#include <stdio.h>

#pragma pack (4)

class Base
{
public:
Base(){}
virtual ~Base(){}

virtual void TestBase();

int t;
int t1;
int t2;
int t3;
int t4;
int t5;
int t6;
int t7;
int t8;
};

void Base::TestBase()
{

}

class Father : public Base
{
public:
Father()
{

}

virtual ~Father()
{

}

virtual void Test();

int a;
};

void Father::Test()
{

}

class Mother : public Base
{
public:
Mother()
{

}

virtual ~Mother()
{

}

virtual void TestM();
};

void Mother::TestM()
{

}

class Son : public Father, public Mother
{
public:
Son()
{

}

virtual ~Son()
{

}

virtual void Test1();
};

void Son::Test1()
{

}

int main()
{
int base = sizeof(Base);
int father = sizeof(Father);
int mother = sizeof(Mother);
int son = sizeof(Son);
}

father = 44;

son = 84;

mother = 40;

base = 40;

虚继承

#include <stdio.h>

#pragma pack (4)

class Father
{
public:
Father(){}
virtual ~Father(){}
};

class Mother
{
public:
Mother(){}
virtual ~Mother(){}
};

class Child1 : public virtual Father, public virtual Mother
{
Child1(){}
virtual ~Child1(){}
};

class Child2 : public virtual Father
{
Child2(){}
virtual ~Child2(){}
};

int main()
{
int a = sizeof(Father);
int b = sizeof(Mother);
int c = sizeof(Child1);
int d = sizeof(Child2);
}

a=4

b=4

c=12

d=8
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: