目录
一.程序启动所关联的内存分区
.dll文件是Dynamic Link Library(动态链接库)文件的缩写,它是一种共享库文件,包含了程序所需的代码和数据。与静态链接库不同,动态链接库可以在程序运行时动态加载,使得程序的内存占用更小,同时也方便了程序的更新和维护。
程序启动时,系统会将exe主程序依赖的所有dill库文件加载到进程的代码段的内存区中,这些文件里存放的是可执行的二进制机器码,也就是汇编代码。
等到所有的dill模块都加载完毕后,才将exe主程序加载到进程空间,之后启动C/C++运行时库,然后给全局变量分配内存并执行全局变量的初始化操作,此处对应的是全局内存区,然后才会进入到main函数,程序启动。
当执行函数时,在当前线程栈内存上给函数的局部变量申请栈内存,如果执行的是malloc或者new的代码,申请的就是堆内存。
二.动态内存的申请和释放
在C/C++中,动态申请的内存是需要开发人员自己去管理的,即使用完毕后需要手动去释放,否则就会造成内存泄漏,产生严重bug。
三.C++中使用new去申请内存,用delete来释放内存
C++在支持malloc和free动态申请内存的基础上,新增new和delete两种方式,new主要是用来new出一个C++对象来,也就是在堆内存上申请一个C++对象的内存,不用时调用delete释放掉。
new一个C++对象时,不仅会在堆上申请内存,还会调用该对象的构造函数,具体来说,是先申请内存,再调用构造函数。
同样的,delete时,会调用该对象的析构函数,具体来说,是先调用析构函数,然后释放掉对象所占堆内存。
需要注意的是,new出来的对象不会自动调用析构函数,需要我们手动去delete。
三.将RAII思想融入代码
这样一来,如果程序很复杂,那delete就会很繁琐并且容易出错,所以,我们编程时就需要融入RAII(Resource Acquistion Is Intialization)思想。
当我们在main函数中声明一个局部对象的时候,会自动调用构造函数进行对象的初始化,当整个main函数执行完成后,自动调用析构函数来销毁对象,整个过程无需人工介入,由操作系统自动完成;于是,很自然联想到,当我们在使用资源的时候,在构造函数中进行初始化,在析构函数中进行销毁。整个RAII过程我总结四个步骤:
a.设计一个类封装资源
b.在构造函数中初始化
c.在析构函数中执行销毁操作
d.使用时声明一个该对象的类
下面是基于RAII思想实现的一个简单的互斥锁。
四.RAII思想的简单应用
#include<pthread.h>
#include<iostream>
class Mutex
{
private:
/* data */
pthread_mutex_t *_mutex;
public:
Mutex(pthread_mutex_t *mutex);
~Mutex();
void Lock()
{
std::cout<<"Initialize Success"<<std::endl;
pthread_mutex_lock(_mutex);
}
void UnLock()
{
std::cout<<"Delete Success"<<std::endl;
pthread_mutex_unlock(_mutex);
}
};
Mutex::Mutex(pthread_mutex_t* mutex) :_mutex(mutex)
{
}
Mutex::~Mutex()
{
}
class LockGuard
{
private:
Mutex _mutex;
public:
LockGuard(pthread_mutex_t *mutex);
~LockGuard();
};
LockGuard::LockGuard(pthread_mutex_t* mutex) :_mutex(mutex)
{
_mutex.Lock();
}
LockGuard::~LockGuard()
{
_mutex.UnLock();
}
int main()
{
pthread_mutex_t mutex;
LockGuard lockGuard(&mutex);
return 0;
}
运行代码,自动调用构造函数和析构函数,不用我们手动删除,非常方便。
需要注意Delete Success是在return 0之后才打印的。