[toc]
内存空间的布局
◼ 每个应用都有自己独立的内存空间,其内存空间一般都有以下几大区域
- 代码段(代码区)
✓ 用于存放代码
- 数据段(全局区)
✓ 用于存放全局变量等
- 栈空间
✓ 每调用一个函数就会给它分配一段连续的栈空间,等函数调用完毕后会自动回收这段栈空间
✓ 自动分配和回收
- 堆空间
✓ 需要主动去申请和释放
image-20210402175647608
堆空间
◼ 在程序运行过程,为了能够自由控制内存的生命周期、大小,会经常使用堆空间的内存
◼ 堆空间的申请\释放
- 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调用和表层语法糖,对性能优化无从下手
堆空间的初始化
image-20210402191223941
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等)
image-20210402192057775
构造函数(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分配的对象不会调用构造函数==
image-20210402193042103
struct Person {
int m_age;
Person() {
m_age = 0;
cout << "Person()" << endl;
}
};
int main() {c
Person person0; // Person()
}
//输出 : Person()
看汇编码的话 LLDB 里用 disas
命令
disas
image-20210402194028957
struct Person {
int m_age;
};
int main() {
Person person0; // Person()
person0.m_age = 10;
}
image-20210402194523151
当没有默认的构造函数的时候,可以供汇编代码可以看到,整个汇编代码执行,只有一句操作movl $0xa, -0x8(%rbp)
,没有任何call函数调用的初始化操作。
struct Person {
int m_age=8;
};
image-20210402195126458
==在某些特定的情况下,编译器才会为类生成空的无参的构造函数==
成员变量的初始化
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()
image-20210402202742175
image-20210402202900550
image-20210402203013917