1 内存分配方式

1.1 简介

  • :存储函数内局部变量,函数执行结束时存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限
  • :就是那些由malloc分配的内存块。
  • 自由存储区:就是那些由new分配的,已经分配了内存却并未初始化的内存。可以用void*操作,但无法获得对象。
  • 全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
  • 常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

1.2 区分堆与栈

void f() {
    int* p=new int[5];
    delete []p;
}

程序分配了一块堆内存,又在栈内存中存放了一个指向一块堆内存的指针p

1.3 堆和栈主要区别

  • 管理方式:堆的释放工作由程序员控制,容易产生memory leak;栈是由编译器自动管理,无需我们手工控制。
  • 空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间。但是对于栈来讲,一般都是有一定的空间大小的,如1M。
  • 碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列。
  • 生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
  • 分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配是由编译器进行释放
  • 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间。显然,堆的效率比栈要低得多。

2 控制C++的内存分配

你需要用一个全局的newdelete来代替系统的内存分配符,并且一个类一个类的重载newdelete。一个防止堆破碎的通用方法是从不同固定大小的内存池中分配不同类型的对象。对每个类重载newdelete就提供了这样的控制。

对于多数C++的实现,new[]操作符中的个数参数是数组的大小加上额外的存储对象数目的一些字节。在你的内存分配机制重要考虑的这一点。你应该尽量避免分配对象数组,从而使你的内存分配策略简单。

class TestClass {
    public:
    void * operator new(size_t size);
    void operator delete(void *p);
    void * operator new[ ](size_t size);
    void operator delete[ ](void *p);
};
void *TestClass::operator new(size_t size){
    void *p = malloc(size);
    return (p);
}
void TestClass::operator delete(void *p){
    free(p); 
}
void *TestClass::operator new[ ](size_t size){
    void *p = malloc(size);
    return (p);
}
void TestClass::operator delete[ ](void *p){
    free(p);
}

3 常见的内存错误及其对策

  • mallocnew申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
  • 不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
  • 避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
  • 动态内存的申请与释放必须配对,防止内存泄漏。
  • freedelete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

4 指针与数组的对比

修改内容

char a[] = "hello";
a[0] = 'X';
cout << a << endl;

char *p = "world"; // 注意p指向常量字符串
p[0] = 'X'; // 编译器不能发现该错误
cout << p << endl;

计算内存容量

char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12字节
cout<< sizeof(p) << endl; // 指针自身的内存容量,4字节

5 使用动态内存的情况

  • 程序不知道需要多少对象:容器类
  • 程序不知道对象的准确类型
  • 程序需要在多个对象间共享数据:浅拷贝

ShengYg

Step after step the ladder is ascended.


Tags •