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.常量存储区
比较特殊的存储区,存放的是常量,不允许修改。
函数的变量在内存中的地址:
运行结果:
我们发现,函数参数的地址是递增的,局部变量的地址是递减的(分配在堆上)。当使用char,short,int时候地址增量为4,当使用double时地址增量为8,当使用引用时参数的地址与被引用对象的地址一致,如果内用的是是一个指针,那引用参数的地址与指针内存地址一致。对于new的内存,地址增量为12,对于double和int都一样。
再来看下如果局部变量分配在栈上会怎么样?
对于局部变量在栈上的地址,int型增量是12,double型增量是16。
以上结果使用win7 64位操作系统 vs2013 Win32程序
内存字节对齐:
为什么要进行字节对齐:效率。计算机从内存中取数据是按照一个固定长度的。以32位机为例,它每次取32位也就是4个字节。以int为例,如果它在内存中存放的位置按5字节对齐,也就是说1个int的数据全部落在计算机一次区数据的区间内,那么只需要取一次就可以了。如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,这样效率就降低了。内存对齐是典型的以空间换效率的方法。
结构体内成员按自身长度进行对齐。当未明确指定时,以结构体中最长的成员长度为齐有效值。当用#pragma pack(n)指定时,以n和结构体中最长的成员的长度中较小者为齐对齐。当用__attribute__ ((__pack__))指定长度时,强制按照此值为结构体的有效对齐值。
空类内存大小为1字节
继承时候内存占用:
普通继承
son = 8;
继承有成员函数
father = 4;
son = 8;
继承有虚函数
father = 8;
son = 12;
继承基类与派生类都有虚函数
father = 8;
son = 12;
多继承
father = 8;
son = 12;
mother = 4;
多继承
father = 12;
son = 20;
mother = 8;
虚继承
son = 28;
mother = 16;
base = 8;
虚继承
father = 52;
son = 60;
mother = 48;
base = 40;
不用虚继承
father = 44;
son = 84;
mother = 40;
base = 40;
虚继承
a=4
b=4
c=12
d=8
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
相关文章推荐
- c语言:通过指向结构体变量的指针变量输出结构体变量中成员的信息
- c++类的基础
- C++ 实现比较版本号
- C++ STL stack/queue
- C++ 学习之路(9):(附C++程序的多文件组成)堆栈示例
- C++第2次上机实验-C++程序的编写和运行
- 1013_三角形判断
- c++实现线性表
- c语言实现线性表
- C++中指针与数组的详解
- C语言-for循环
- C语言inline详细讲解
- C++编程采用windows API实现GBK转UTF-8
- c++基础
- VC++ 监控指定目录改变
- C++之伪函数
- C++项目中的extern "C" {}
- C++中颜色的设置
- C++Socket
- 在初学C语言容易忽略的函数-scanf()函数与printf()函数