内存释放
Windows内核调试
内存释放
yushang
2009-09-15, 19:25 下午
有时候需要使用一个函数返回的内存指针(字符串指针),但是这个指针有可能指向动态分配的内存也可能指向常量区,显然如果是常量区,调用者不能做释放。有没有一个简单的办法判断一个指针是动态分配还是指向常量区呢?
Re: 内存释放
dos
2009-09-16, 17:46 下午
不知道楼主的问题上下文是什么,发现是在“windows内核”版发的帖,可能指的是在编写驱动程序遇到的问题吧。
不过这个问题具有普遍性,普通c/c++应用程序同样会有这样的问题。同样会碰到诸如调用一个函数,得到一个指向一个字符串的指针等...
楼主的要求是“如何判断一个指针指向的地址是动态分配的空间还是常量区”。
这个...我目前还没有头绪,呵呵~
不过,幸好,楼主的帖子表明了楼主的需求,那就是“释放用完后应该被释放的内存,避免出现内存泄漏”。
这个,我倒是有些思路:)
记得有个原则,那就是“谁分配谁释放”。
楼主可以采用这个原则,来跟那个提供返回内存指针的函数协作。即让这个函数的实现者在如下2个方案中做一个选择:
1、被调用者分配释放内存。要求函数实现者再提供一个释放指针的函数,参数就是那个返回的指针。因为是函数实现者产生的这个指针,所以他也应该知道如何释放它,以及该不该释放它。c/c++运行库的一些函数用的就是这种原则,如malloc/free new/delete,
2、调用者分配释放内存。这需要修改函数原型,增加一个参数,这个参数是一个指针,调用者负责给这个指针分配好空间,再作为参数传到函数中,函数实现者直接使用该指针分配好的空间。函数返回后,是否该释放该指针,调用者是应该知道的。c/c++标准库的strcpy用的就是这个原则,它的第一个参数是要求调用者分配好空间的。还有一些 windows API的参数,也是要求调用者负责分配好空间。
至于让函数实现者在函数的参数中增加一个flag,标识返回的指针是否需要释放,或者调用者使用奇技淫巧自己判断返回的指针是否需要释放,虽然也可以解决问题,但感觉有些怪怪的。
如果是hack一个东西,使用什么方法倒是无所谓,“不管白猫黑猫,能抓到老鼠的就是好猫”嘛。
如果是做软件产品,设计上遵循“谁分配谁释放”的原则可能会更好些。
Re: 内存释放
yushang
2009-09-17, 08:24 上午
呵呵,很不巧,我刚好用的是“你分配我释放“的方式:
BOOLEAN SomeAlloc(PULONG *ptr)
通过函数返回值确定是否是动态分配,通过ptr返回内存指针。调用者根据函数返回值决定是否释放。
你说的方法1是否存在额外的开销?对于分配的每片内存肯定要维护一个和该片内存关联的信息,释放的时候根据对应的信息决定是否需要真正的释放。
方法2不适合我的情况,我这里刚好是调用者没有任何该怎么分配内存的知识(因为分配的内存还需要填充好一定的内容),它必须要调用另一个函数。
我猜测,动态分配的内存指针是否会一定大于某个值,而常量区内存一定会小于某个值呢?不过就算这个方法可行,好像也没有精简多少,至多上面这个分配函数少返回一个值而已,谢谢,这个问题已经解决。
Re: 内存释放
王宇
2009-09-17, 09:12 上午
“你分配我释放”,那就要求再加一个参数,表明分配类型。
如果是内核,可以加一个 POOL_TAG 参数,然后往前搜索、对比 TAG。
Re: 内存释放
dos
2009-09-17, 10:46 上午
祝贺楼主问题解决!呵呵~
不过针对楼主目前的解决方法以及遵循“谁分配谁释放”原则的好处,我还想啰嗦几句,唉~人老了,就爱唠叨,呵呵~...
假设一种情况,调用者根据返回值,发现该内存需要释放,那么如何释放呢?
delete ptr?
delete[] ptr?
如果函数实现者是个忠实的c fans,使用了malloc分配了空间,是否相应的应该用free(ptr)?
或者调用者是个过度喜欢c++的fans,为了数据操作上的方便,new 了一个c++的类(还在类的析构函数里释放了操作中需要的一些临时空间,呵呵~有些变态哈,要不说是过度的C++ fans呢),不过在返回的时候将类指针强制转换成了PULONG类型的指针,那调用者是不是要向函数实现者强索那个类结构,然后delete (SomeClass*)ptr?
或者实现者为了某种BT的原因,其实是new了一个SomeClass的数组,那调用者是不是要用delete[] (SomeClass*)ptr?
楼主可能说了,呵呵~不会有这么多问题的,函数的实现是,如果用了需要释放的内存,那空间就是用new PULONG[xx]产生的,而且,函数接口开发文档上也说明白了,返回的指针在返回值是某某某的情况下,需要用delete[] 来释放....
唔~...听起来好像也没有问题哈。
所以,我说的是如果是产品,呵呵~
是产品,就会不断改进,会有长期的维护。
假设有一天,这个函数的实现代码移交给了另一个上面提到的某个c或c++ fans,那可能会发生什么呢?......
我听到有声音说,“标考虑那么多情况嘛,“过度设计”是有害的哦....”
呵呵~...其实遵循一个“原则”跟“过度设计”还是不一样的。
“过度设计”是在实现前,先考虑各种情况,然后我们要针对这些各种情况,想出一个解决方案来,这就可能延误产品开发,可能使系统复杂....
遵循某个“原则”是已经有一个方案,然后“不小心”发现这个原则,原来可以cover很多种情况,这个原则是不需要我们想的,不会让系统复杂(有时候反而会让系统更简单、更易于理解),不会延误开发进度,拿来用就好了...
晕~...我都觉得自己啰嗦了,唉....
Re: 内存释放
dos
2009-09-17, 11:31 上午
哦,想起来了,按楼主的实现方式,还有一个地方需要注意,那就是,如果这个函数是作为dll发布给使用者的话,要发布两个版本,debug版本和release版本。
并且说明,如果使用者的模块是debug方式编译的,也要使用该dll的debug版;如果使用者的模块是release版,也要使用dll的release版本。
为什么呢?
简单地说,是因为debug方式分配的内存,不能用release的方式释放,反之亦然。
这个问题不是想象出来的,是我们很早以前碰到过,不敢专有,跟楼主分享下。:)
后来怎么解决的这个麻烦我忘记了,不过,用“谁分配谁释放”的原则,应该是不会出现这种麻烦了,呵呵~...
Re: 内存释放
yushang
2009-09-17, 17:23 下午
呵呵,这个倒是第一次听说,我猜测原因如下:
1。常见的内存管理技术都是在分配给用户的内存前/后加上一些附加信息,内存管理函数根据用户指针推导出真正需要释放的地址
2。debug版的内存分配函数和release版的内存分配函数使用的附加信息大小是不一致的
3。debug版的dll会调用debug版的内存分配函数,release版的模块则调用release版的内存释放函数时按照release版的指针来推导真正需要释放的地址,所以会出错
这样对吗?