巧用对象的机制构造局部堆自动清理内存助手
来源:互联网 发布:淘宝卖家遭遇诈骗 编辑:程序博客网 时间:2024/06/08 19:10
1 简说
本文是自己工作的一点经验和一些想法。
其实也不算什么新颖的技术,因为局部锁,局部光标画面等都是通过巧用对象的构造和析构来自动初始化和清理。本文所说也是。
欢迎高手和老手指点
2 问题的提出
常常担心在代码中,有内存泄露的现象,所以不得不在函数体内的每个返回值做对内存的清理操作(或者一些goto,然后统一对内存清理)。对于在函数体内申请的内存块少的时候,代码短
小的,并没有什么,但是如果申请内存卡多了,总会影响一下代码的优美或者担心某块内存没有被释放。如果有个机制,使得我们申请的内存,自动释放,那是多么美好的事情!
3 初探
封装一个类,用于作为内存块的管理助手,主要是构造时候帮忙申请内存,析构时候帮忙释放内存,这样就可以确保自己在函数体申请的内存在函数推出时候释放了,而不用当心有内存泄露
。
实现如下:
CLocalHeapHelper
{
public:
CLocalHeapHelper(void **p, unsigned int cbSize)
{
if (cbSize == 0 || p == NULL || *p != NULL) { // 判断*p != NULL ,主要不对未初始化的指针或者已经申请过内存的指针进行操作。
return;
}
m_ptr = malloc(cbSize);
*p = m_ptr;
}
~CLocalHeapHelper()
{
if (m_ptr != NULL) {
free(m_ptr);
m_ptr = NULL;
}
}
protected:
void *m_ptr;
};
使用
void Test()
{
STRUCT_1 *p_1 = NULL;
CLocalHeapHelper Helper1((void **)&p_1, sizeof(STRUCT_1));
if (p_1 == NULL) {
return;
}
// dosomething
STRUCT_2 *p_2 = NULL;
CLocalHeapHelper Helper_2((void **)&p_2, sizeof(STRUCT_2));
if (p_2 == NULL) {
return;
}
// dosomething
//……
STRUCT_n *p_n = NULL;
CLocalHeapHelper Helper_n((void **)&p_n, sizeof(STRUCT_n));
if (p_n == NULL) {
return;
}
// dosomething
}
这样 在函数返回,就不用担心在函数返回时候有泄漏内存了,也没有必要加个goto 然后Clear。保持了代码的整洁。
4 改进
开始时候,在处理局部堆内存块时候,我是这样封过这样的类来用过,开始觉得挺不错的,但慢慢,在一些函数内部,申请的内存块比较多的是很,就不得不构造多个局部堆清理内存对象来
处理,细细想,其实是没有必要每块内存块都关联着一个对象的,所有内存块关联到一个对象里面去就可以了,只是那个对象要多维护一个链表。
再封装个类大概如下(实现在文章的最后 - 因为这不是重要的,各人根据需要来封装就行了):
class CLocalHeapMgr
{
public:
CLocalHeapMgr();
~CLocalHeapMgr(); // 析构时候对说有通过本对象Malloc的内存块都释放
void *Malloc(unsigned int cbSize);
public:
void Free(void *ptr);// 释放已经清理过的ptr
void ClearHeap(); // 释放CLocalHeapMgr所有申请过的内存块
protected:
typedef struct _LOCAL_HEAP_ITEM {
_LOCAL_HEAP_ITEM *pNext;
void *ptr;
} LOCAL_HEAP_ITEM, *PLOCAL_HEAP_ITEM;
LOCAL_HEAP_ITEM m_head; // 浪费一个节点作为头节点,方便一下实现。
};
这样封装之后,上面的测试函数就可以进一步简化了:
void Test()
{
CLocalHeapMgr lhHelper;
STRUCT_1 *p_1 = lhHelper.Malloc(sizeof(STRUCT_1));
if (p_1 == NULL) {
return;
}
// dosomething
STRUCT_2 *p_2 = lhHelper.Malloc(sizeof(STRUCT_2));
if (p_2 == NULL) {
return;
}
// dosomething
//……
STRUCT_n *p_n = lhHelper.Malloc(sizeof(STRUCT_n));
if (p_n == NULL) {
return;
}
// dosomething
}
其实 void Free(void *ptr);和 void ClearHeap();本来可以不要的,因为 如果加了这个函数,比如在函数体用了lhHelper.Malloc()了,还用用一下lhHelper.Free()或者
lhHelper.ClearHeap(),这样和自己申请,自己释放有什么区别呢?这个对象就有点多次一举了。
在开始封装这个类时候,也没有打算要这两个接口的,后来想,如果在一些循环内部申请内存的话(或者申请过多内存了,而且这些内存块也不用了的),清理一下也可以减少下进程占内存
的大小。所以就画蛇添足加了这两个接口。
5 存在问题
就是因为public了void ClearHeap(); 这个接口,导致了一个隐瞒的小问题,比如
{
……
CLocalHeapMgr lhHelper;
STRUCT_1 *p_1 = lhHelper.Malloc(sizeof(STRUCT_1));
// dosomething
STRUCT_2 *p_2 = lhHelper.Malloc(sizeof(STRUCT_2));
// dosomething
lhHelper.ClearHeap();
//……
STRUCT_n *p_n = lhHelper.Malloc(sizeof(STRUCT_n));
// dosomething
}
在调用lhHelper.ClearHeap()之后,如果不置p_1 p_2 为NULL,那么它们是野指针了的,如果忘记了又用的时候,不得了~~~~(>_<)~~~~ 。当然,调用Free 或者ClearHeap() 就应该确定之前
的指针都不能再用了的。
然而,也可以再修改封装类来解决这个问题,(有点感觉 类越封装,就越臃肿了~~)
就是在
CLocalHeapMgr的void *Malloc(unsigned int cbSize); 改成void Malloc(void **pAddr, unsigned int cbSize); 把申请的指针地址也一起关联到链表里面去,在LOCAL_HEAP_ITEM中再增加
一个节点来保存这个地址即可,在释放某块内存的时候,同时也把关联着的那个指针也置为NULL 就行了。这个就不去实现了,感觉那样封装,不好看^_^。
6 破代码:
CLocalHeapMgr::CLocalHeapMgr()
{
m_head.pNext = NULL;
m_head.ptr = NULL;
}
CLocalHeapMgr::~CLocalHeapMgr()
{
this->ClearHeap();
}
void *CLocalHeapMgr::Malloc(unsigned int cbSize)
{
if (cbSize == 0) {
return NULL;
}
LOCAL_HEAP_ITEM *pNewItem = (LOCAL_HEAP_ITEM *)malloc(sizeof(LOCAL_HEAP_ITEM));
if (pNewItem == NULL) {
return NULL;
}
pNewItem->ptr = malloc(cbSize);
if (pNewItem->ptr == NULL) {
free(pNewItem);
pNewItem = NULL;
return NULL;
}
memset(pNewItem->ptr, 0, cbSize);
pNewItem->pNext = m_head.pNext;
m_head.pNext = pNewItem;
return pNewItem->ptr;
}
void CLocalHeapMgr::Free(void *ptr)
{
if (ptr == NULL) {
return ;
}
LOCAL_HEAP_ITEM *pTraverItem = &m_head;
LOCAL_HEAP_ITEM *pFreeItem = NULL;
while (pTraverItem->pNext != NULL) {
if (pTraverItem->pNext->ptr == ptr) {
break;
}
pTraverItem = pTraverItem->pNext;
}
if (pTraverItem->pNext == NULL) { // not find
return;
}
pFreeItem = pTraverItem->pNext;
pTraverItem->pNext = pFreeItem->pNext;
free(pFreeItem->ptr);
free(pFreeItem);
pFreeItem = NULL;
}
void CLocalHeapMgr::ClearHeap()
{
LOCAL_HEAP_ITEM *pTraverItem = m_head.pNext;
LOCAL_HEAP_ITEM *pTraverNext = NULL;
m_head.pNext = NULL;
while (pTraverItem != NULL) {
pTraverNext = pTraverItem->pNext;
free(pTraverItem->ptr);
free(pTraverItem);
pTraverItem = pTraverNext;
}
}
- 巧用对象的机制构造局部堆自动清理内存助手
- android内存自动清理机制和android垃圾回收器
- 堆内存的GC机制
- linux自动内存清理
- 内存管理(一):栈区、堆区,成员变量和局部变量,alloc,retain,自动释放池,成员变量及属性的内存管理
- 简单的链表与自动清理内存
- Qt中特有的类对象机制——内存自动释放
- 好用的Mac清理内存工具
- 清理内存的程序
- iOS_Runtime_OC对象在堆内存中开辟内存的大小
- NO7.java学习笔记【面向对象、栈内存、堆内存、构造函数、this、super、继承、覆盖、对象实例化、final】
- VC项目清理助手
- 【源码】VS2010清理助手
- 垃圾文件清理助手
- C#堆栈及托管堆的内存创建机制
- Java内存机制(堆与栈)的分配-转帖
- C中堆与栈的内存分配机制
- Java的内存机制(堆和栈)简单理解
- 0.8.11版本ffmpeg一天移植将近完成。
- 新W3C标准中 AJAX 跨域实现以及隐患
- android 无缝连续播放
- 异常的总结
- jquery判断checkbox(复选框)是否被选中的代码
- 巧用对象的机制构造局部堆自动清理内存助手
- 【初识eclipse 第一讲】 eclipse 的基本使用
- java并集差集交集
- SQL语句更新时间字段的年份、月份、天数、时、分、秒
- 收集整理的大公司面试中与编程相关题目
- SQL注入漏洞全接触--入门篇
- Java开发工具类
- hdu 2642 Stars
- javaEE之JPA、EJB、JSF架构工程