C++内存空间管理

1.C++内存机制

1.栈(Stack),函数中的局部变量,由编译器负责分配释放,函数结束,变量释放。

2.堆(Heap),通过new 申请的内存,由delete或delete[]释放

3.自由存储区(Free Storage),由程序员用malloc,calloc/realloc分配,free进行释放,忘记free,会导致内存泄漏,程序结束时,该区域内存由OS回收

4.全局区/静态区(Global Static Area),全局变量和静态变量存储区。程序编译完成后,该区域便存在,在C++中,由于全局变量和静态变量编译器会给这些变量自动初始化赋值,所以没区分初始化变量和未初始化变量。由于全局变量一直占据内存空间且不易维护,推荐少用,程序结束时释放。

5.常量存储区,比较特殊,专门存储不能修改的变量。

注意事项

【规则1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL,防止使用指针值为NULL的内存,可以在函数入口处断言检测。

【规则2】不要忘记为数组或动态内存赋初值(比如calloc比malloc就要好),指针初始化为NULL(c++中为0)。

【规则3】避免数组或指针下标越界,特别

当心发生“多1”或者"少1"的操作。

【规则4】动态内存的申请和释放必须配对,防止内存泄露,具体为malloc/calloc/realloc和free配对,new和delete以及delete[]配对。

【规则5】用free或者delete释放内存后,应立即将指针设置为NULL(C++中为0),防止产生“野指针”、"悬垂指针"。

【规则6】遇到不懂得问题及时debug,一般的虫子

debug一下就灰飞烟灭了,一切bug都是浮云而已

内存管理分为

一.内存管理机制

二.内存泄漏机制

三.内存回收机制

内存溢出:程序在申请内存时,没有足够的内存空间供其使用

内存泄漏:程序在申请内存后,无法释放已申请的内存空间,占用有用内存,最终导致内存溢出

/******************************************************

内存空间的布局

◼ 每个应用都有自己独立的内存空间,其内存空间一般都有以下几大区域

  • 代码段(代码区)

✓ 用于存放代码

  • 数据段(全局区)

✓ 用于存放全局变量等

  • 栈空间

✓ 每调用一个函数就会给它分配一段连续的栈空间,等函数调用完毕后会自动回收这段栈空间

✓ 自动分配和回收

  • 堆空间

✓ 需要主动去申请和释放

堆空间

◼ 在程序运行过程,为了能够自由控制内存的生命周期、大小,会经常使用堆空间的内存

◼ 堆空间的申请\释放

  • malloc \ free
  • new \ delete
  • new [] \ delete []

char *p = (char *) malloc(4);
p[0] = 10;
p[1] = 11;
p[2] = 12;
p[3] = 13;
free(p);

int *p = (int *) malloc(4);
*p = 10;
free(p);

 

X86环境(32bit)

int *p = new int;
*p = 10
delete p;

char *p = new char;
*p = 10;

delete p;

char *p = new char[4];

delete[] p;

◼ 注意

  • 申请堆空间成功后,会返回那一段内存空间的地址
  • 申请和释放必须是1对1的关系,不然可能会存在内存泄露

◼ 现在的很多高级编程语言不需要开发人员去管理内存(比如Java),屏蔽了很多内存细节,利弊同时存在

  • 利:提高开发效率,避免内存使用不当或泄露
  • 弊:不利于开发人员了解本质,永远停留在API调用和表层语法糖,对性能优化无从下手

堆空间的初始化

memset

◼ memset函数是将较大的数据结构(比如对象、数组等)内存清零的比较快的方法

int size = sizeof(int) * 10;
int *p = (int *) malloc(size);
// memory set
memset(p, 0, size);

int *p0 = new int;
int *p1 = new int();
int *p2 = new int(5);

cout << *p0 << endl;
cout << *p1 << endl;
cout << *p2 << endl;

0 (mac)下为0
0
5

对象的内存

◼ 对象的内存可以存在于3种地方

  • 全局区(数据段):全局变量

  • 栈空间:函数里面的局部变量

  • 堆空间:动态申请内存(malloc、new等)

构造函数(Constructor)

◼ 构造函数(也叫构造器),在对象创建的时候自动调用,一般用于完成对象的初始化工作

struct Person {
   int m_age;

   Person() {
      m_age = 0;
      cout << "Person()" << endl;
   }

   Person(int age) {
      m_age = age;
      cout << "Person(int age)" << endl;
   }
};

◼ 特点

  • 函数名与类同名,无返回值(void都不能写),可以有参数,可以重载,可以有多个构造函数

  • 一旦自定义了构造函数,必须用其中一个自定义的构造函数来初始化对象

◼ 注意

  • 通过==malloc分配的对象不会调用构造函数==

struct Person {
   int m_age;

   Person() {
      m_age = 0;
      cout << "Person()" << endl;
   }
};
int main() {c
    Person person0; // Person()
}
//输出 : Person()

看汇编码的话 LLDB 里用 disas 命令

disas

struct Person {
    int m_age;
};
int main() {

    Person person0; // Person()
    person0.m_age = 10;
    
}

当没有默认的构造函数的时候,可以供汇编代码可以看到,整个汇编代码执行,只有一句操作movl $0xa, -0x8(%rbp),没有任何call函数调用的初始化操作。

struct Person {
    int m_age=8;
};

==在某些特定的情况下,编译器才会为类生成空的无参的构造函数==

成员变量的初始化

struct Person {
   int m_age;

};

// 全局区:成员变量初始化为0
Person g_person;

void test() {
   // 栈空间:没有初始化成员变量
   // Person person; 

   // 堆空间:没有初始化成员变量
   Person *p0 = new Person;
   // 堆空间:成员变量初始化为0
   Person *p1 = new Person();

   cout << g_person.m_age << endl;
   // cout << person.m_age << endl;
   cout << p0->m_age << endl;
   cout << p1->m_age << endl;
}

析构函数(Destructor)

◼ 析构函数(也叫析构器),在对象销毁的时候自动调用,一般用于完成对象的清理工作

◼ 特点

  • 函数名以~开头,与类同名,无返回值(void都不能写),无参,不可以重载,有且只有一个析构函数

◼ 注意

  • 通过malloc分配的对象free的时候不会调用析构函数

◼ 构造函数、析构函数要声明为public,才能被外界正常使用

class Person {
   int m_age;
public:
   // 新的Person对象诞生的象征
   Person() {
      cout << "Person::Person()" << endl;
   }

   // 一个Person对象销毁的象征
   ~Person() {
      cout << "~Person()" << endl;
   }
};

using namespace std;

struct Car {
   int m_price;

   Car() {
      m_price = 0;
      cout << "Car::Car()" << endl;
   }

   ~Car() {
      cout << "Car::~Car()" << endl;
   }
};

struct Person {
private:
   int m_age;
   Car *m_car;
public:
   // 用来做初始化的工作
   Person() {
      m_age = 0;
      m_car = new Car();
       
      cout << "Person::Person()" << endl;
   }

   // 用来做内存清理的工作
   ~Person() {
      delete m_car;
      cout << "Person::~Person()" << endl;
   }
};

int main() {
   {
      Person person;
   }

   int age = 20;
   int *p = &age;

   return 0;
}

Car::Car()
Person::Person()
Car::~Car()
Person::~Person()



 

  • 7
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值