内存管理是计算机编程最为基本的领域之一。在很多脚本语言中,您不必担心内存是如何管理的,这并不能使得内存管理的重要性有一点点降低。对实际编程来说,理解您的内存管理器的能力与 局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存管理。本文将介绍手工的、 半手工的以及自动的内存管理实践的基本概念。
IBM 内存管理介绍
第一级配置器以 malloc(),free(),realloc()等C函数执行实际的内存配置、释放、重新配置等操作,并且能在内存需求不被满足的时候,调用一个指定的函数
第二级配置器维护着16个空闲链表(free list),各自管理大小分别为8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128 bytes的小内存块。
如果要分配的内存大于 128bytes,则移交给第一级配置器处理,直接用malloc。
如果要分配的内存小于 128bytes,则以内存池管理(memory pool),使用第二级配置器,找出适合的空闲链表, 从其上摘下一个节点将其头指针返回给用户,这就完成了对用户的内存分配。
释放过程则正好与分配相对应,如果用户分配的内存大于128bytes,直接用free,否则找出适当的空闲链表, 将指针所指的该段内存重新连接到空闲链表中(注意此时并不把内存返回给操作系统, 如此可以重复利用)。
小内存块(空闲链表管理)–> 大内存块(malloc 向OS申请)
使用 allocate 请求size大小的内存空间, 如果需要请求的内存大小大于128bytes, 直接使用malloc.
如果需要的内存大小小于128bytes, allocate根据size找到最适合的空闲链表.
a. 如果链表不为空, 返回第一个内存块, 链表头改为第二个内存块。
b. 如果链表为空, 使用refill为该空闲链表填充新的空间。
x. 如果内存池中有大于一个内存块的空间, 分配尽可能多的内存块(但是最多20个), 将一个内存块返回, 其他的内存块添加到链表中。
y. 如果内存池只有一个内存块的空间, 直接返回给用户.
z. 如果内存池连一个内存块的空间都没有, 再次向操作系统请求分配内存.
I 系统内存足够,分配成功,再次进行b过程
II 分配失败, 循环各个空闲链表, 寻找空间
A. 找到空间, 再次进行过程b
B. 找不到空间, 抛出异常
用户调用deallocate释放内存空间, 如果要求释放的内存空间大于128bytes, 直接调用free。
否则按照其大小找到合适的空闲链表, 并将其插入。
特点其实是这样的:
刚开始初始化内存池的时候, 其实内存池中并没有内存, 同时所有的空闲链表都为空链表.
只有用户第一次向内存池请求内存时, 内存池会依次执行上述过程的 1->2->b->z来完成内存池以及链表的首次填充, 而此时, 其他未使用链表仍然是空的
malloc的全称是memory allocation,中文叫做:动态内存分配。
原型:extern void* malloc(unsigned int num_bytes);
说明:分配长度为num_bytes字节的内存块。如果分配成功,则返回指向被分类内存的指针;如果分配失败,则返回空指针NULL。(所以申请完内存需要判断所申请内存是否为空)当内存不再使用时,应使用free()函数讲内存块释放。
返回类型:void类型,表示通用变体类型指针,c,c++规定,void类型可以强制转换为任何其他类型的指针;void*指申请内存空间时,还不知道用户用这段空间来存储什么类型的数据。
释放:void free(void * FirstByte);讲malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存。
注意事项:
1)申请内存空间后,必须检查是否分配成功;
2)当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,以防后面的程序不小心使用了野指针
3)malloc和free应该配对使用;释放只能释放一次,若释放两次或更多会出现错误,(释放空指针例外,释放空指针其实等于啥都没做,释放空指针多少次都没有问题)
4)malloc从堆里面获得内存;函数返回的指针指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表,当操作系统收到程序的申请时,就会遍历链表,然后寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点分配给程序。
c++中,用new和delete动态创建和释放数组或者单个对象。
动态创建对象时,只需要指定其数据类型,而不必为该对象命名。
delete pi;//释放单个对象
delete [ ] pi;//释放数组
new 和 malloc 细微区别
template <typename T>
class smart_ptrs {
public:
smart_ptrs(T*); //用普通指针初始化智能指针
smart_ptrs(smart_ptrs&);
T* operator->(); //自定义指针运算符
T& operator*(); //自定义解引用运算符
smart_ptrs& operator=(smart_ptrs&); //自定义赋值运算符
~smart_ptrs(); //自定义析构函数
private:
int *count; //引用计数
T *p; //智能指针底层保管的指针
};
template <typename T>
smart_ptrs<T>::smart_ptrs(T *p): count(new int(1)), p(p) {
}
//指针运算符
template <typename T>
T* smart_ptrs<T>::operator->() {
return p;
}
// 解引用
template <typename T>
T& smart_ptrs<T>::operator*() {
return *p;
}
//析构函数
template <typename T>
smart_ptrs<T>::~smart_ptrs() {
if (--*count == 0) {
delete count;
delete p;
}
}
//赋值运算符
template <typename T>
smart_ptrs<T>& smart_ptrs<T>::operator=(smart_ptrs& sp) {
++*sp.count;
if (--*count == 0) {
//自我赋值同样能保持正确
delete count;
delete p;
}
this->p = sp.p;
this->count = sp.count;
return *this;
}