文章目录
- C/C++内存分布
- C语言中动态内存管理方式
- C++内存管理方式
-
operator new与operator delete函数
-
new和delete的实现原理
-
定位new表达式(placement-new)
-
内存泄漏
一、C/C++内存分布
有关内存分配的题目
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
1. 选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?__C__ staticGlobalVar在哪里?_C___
staticVar在哪里?___C_ localVar在哪里?__A__
num1 在哪里?__A__
char2在哪里?_A___ *char2在哪里?_A__
pChar3在哪里?__A__ *pChar3在哪里?__D__
ptr1在哪里?__A__ *ptr1在哪里?__B__2. 填空题:
sizeof(num1) = __40__;sizeof(char2) = __ 5 __; strlen(char2) = __ 4 __;sizeof(pChar3) = __ 4或8 __; strlen(pChar3) = __ 4 __;sizeof(ptr1) = _ _4或8_ _;
二、C语言中动态内存管理方式
C语言中常使用:malloc/calloc/realloc/free
1、malloc()
声明:void * malloc(int n);
含义:在堆上,分配n个字节,并返回void指针类型。
返回值:分配内存成功,返回分配的堆上存储空间的首地址;否则,返回NULL
2、calloc()
声明:void *calloc(int n, int size);
含义:在堆上,分配n*size个字节,并初始化为0,返回void* 类型
返回值:同malloc() 函数
3、recalloc()
声明:void * realloc(void * p,int n);
含义:重新分配堆上的void指针p所指的空间为n个字节,同时会复制原有内容到新分配的堆上存储空间。注意,若原来的void指针p在堆上的空间不大于n个字节,则保持不变。
返回值:同malloc() 函数
4、free()
声明:void free (void * p);
含义:释放void指针p所指的堆上的空间。
返回值:无
三、C++中内存管理方式
1.new/delete操作内置类型
#include<iostream>
using namespace std;
void Test()
{
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间
int* ptr6 = new int[3];
delete ptr4;
delete ptr5;
delete[] ptr6;
}
int main()
{
Test();
return 0;
}
从汇编代码方面:
2.new和delete操作自定义类型
#include<iostream>
using namespace std;
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
A* p1 = (A*)malloc(sizeof(A));
A* p2 = new A(1);
free(p1);
delete p2;
// 内置类型是几乎是一样的
int* p3 = (int*)malloc(sizeof(int)); // C
int* p4 = new int;
free(p3);
delete p4;
A* p5 = (A*)malloc(sizeof(A) * 10);
A* p6 = new A[10];
free(p5);
delete[] p6;
return 0;
}
四、operator new与operator delete函数
1 operator new与operator delete函数
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
2.重载operator new与operator delete
#include<iostream>
using namespace std;
struct ListNode
{
ListNode* _next;
ListNode* _prev;
int _data;
void* operator new(size_t n)
{
void* p = nullptr;
p = allocator<ListNode>().allocate(1);
cout << "memory pool allocate" << endl;
return p;
}
void operator delete(void* p)
{
allocator<ListNode>().deallocate((ListNode*)p, 1);
cout << "memory pool deallocate" << endl;
}
};
class List
{
public:
List()
{
_head = new ListNode;
_head->_next = _head;
_head->_prev = _head;
}
~List()
{
ListNode* cur = _head->_next;
while (cur != _head)
{
ListNode* next = cur->_next;
delete cur;
cur = next;
}
delete _head;
_head = nullptr;
}
private:
ListNode* _head;
};
int main()
{
List l;
return 0;
}
五、new和delete的实现原理
1.内置类型
2.自定义类型
new的原理
1. 调用operator new函数申请空间
2. 在申请的空间上执行构造函数,完成对象的构造
delete的原理1. 在空间上执行析构函数,完成对象中资源的清理工作2. 调用operator delete函数释放对象的空间
new T[N]的原理1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请2. 在申请的空间上执行N次构造函数
delete[]的原理1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
3.malloc/free和new/delete的区别
六、定位new表达式(placement-new)
使用格式:new (place_address) type或者new (place_address) type(initializer-list)place_address必须是一个指针,initializer-list是类型的初始化列表使用场景:定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义 类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
class Test
{
public:
Test()
: _data(0)
{
cout << "Test():" << this << endl;
}
~Test()
{
cout << "~Test():" << this << endl;
}
private:
int _data;
};
void Test()
{
// pt现在指向的只不过是与Test对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
Test* pt = (Test*)malloc(sizeof(Test));
new(pt) Test; // 注意:如果Test类的构造函数有参数时,此处需要传参
}
七、内存泄漏
1.什么是内存泄漏,内存泄漏的危害
void MemoryLeaks()
{
// 1.内存申请了忘记释放
int* p1 = (int*)malloc(sizeof(int));
int* p2 = new int;
// 2.异常安全问题
int* p3 = new int[10];
Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.
delete[] p3;
}
2.内存泄漏分类
3.如何避免内存泄漏
总结:内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。