基础类型
注意:在有的机器上double是4bytes。
类的填充问题
class A {
int a;
short b;
int c;
char d;
};
class B {
double a;
int c;
double d;
int e;
};
类的size计算的基本原则是:
1. 类的单位是以块(Block)计算的,一块等于类中最大成员的size
2. 类的大小是块的整数倍,比如A最大的成员是Int,所以A的size为4的倍数,而B为8的倍数(在这里double为8个byte)
3. 类的对象模型是按声明顺序排序的,也就是一个对象挨着一个对象排序,如果对象相加不到一块的大小,则填充这个类,使其达到块的大小
A和B的大小分别为16和32。
栈和堆以及内存分配
我们分配内存有两种方式,一种是分配在栈上,一种是分配到堆上。
我们在一个作用域上分配的临时变量就是分配在栈上,离开作用域就会自动销毁,常见的场景有传入参数和声明初始化用于循环时的index变量。
典型的栈变量:
int i = 0;
Complex s1(1, 2);
Complex s2(3, 4);
栈对象由系统自动回收,所以我们无需手动删除对象。
而堆对象则需要我们手动删除对象并回收内存,堆对象主要是用molloc和new分配的内存。
Complex* p_s = new Complex(5, 5);
delete p_s;
堆对象给了我们很大的灵活性,但同时也带来了危险。
自由的代价就是永远的警惕!
如果我们分配在堆上分配了内存,但却没有回收,则会造成内存泄漏,短时间运行的程序可能没什么,毕竟程序关闭则所有内存都会回收,但如果是长时间运行的程序则会造成严重的内存浪费问题,影响运行性能。
可以光有堆而没有栈吗?或者反过来呢?
在这里就明确告诉你——不兹慈!
为什么呢?因为栈对象是编译时就已经确定了大小,在运行时就无法分配更多内存了,如果全部是栈对象,那么当我们需要更多内存时就悲剧了。
如果只有堆的话更不行,因为指针是在栈上分配的,可是你连可以分配堆对象的指针对象都没有,怎么分配内存?
Debug和Release模式
在Debug模式下,一个类实际会增加很多调试信息,所以实际在内存中的size远远不止你用sizeof看到的这点。在Release对象中也是会夹杂一点内存的信息,否则系统就不知道从哪里开始回收内存了。
而数组对象和普通对象在内存中的存储方式也不一样,数组对象他会在实际的对象前保存这个数组的长度。而普通对象则不会这么做。
New和Delete以及Array
在用指针在堆上创建对象时,一般使用new
关键字创建用delete
关键字删除。而我们在创建数组时,却必须要使用delete[]
关键字。这是为什么呢?下面我们就来看一下它们内部的实现原理。
delete
关键字回收对象的内存模型,也就是说长条的长方形中所有内存都会被释放,如果该对象是指针,则释放第一个指针对象。
好了,现在你应该知道为什么数组应该使用delete[]
关键字了吧。如果数组不是指针数组那么这两个关键字都可以释放内存,但如果数组是指针数组,那么指针所指向的堆的内存则不会被释放,从而造成大量的内存泄漏!