new[]得到的内存居然不能delete[],WHY,代码比较多,有心者进。
new[]得到的内存居然不能delete[],WHY,代码比较多,有心者进。
《提高C++性能的编程技术》一书源代码中,固定大小对象的内存池,有误,百思不得其解,最终的改正却运行成功,但还是不解。
三个源文件:
//MemoryPool.h
#ifndef MEMORYPOOL_H_
#define MEMORYPOOL_H_
template <class T>
class MemoryPool
{
private:
MemoryPool <T> * next;
enum {EXPANSION_SIZE = 32};
void expandTheFreeList(int howMany = EXPANSION_SIZE);
public:
MemoryPool(size_t size = EXPANSION_SIZE);
~MemoryPool();
inline void* alloc(size_t size);
inline void free(void* doomed);
};
template <class T>
MemoryPool <T> ::MemoryPool(size_t size)
{
expandTheFreeList(size);
}
template <class T>
MemoryPool <T> ::~MemoryPool()
{
MemoryPool <T> * nextPtr = next;
delete nextPtr;//此处为我修改代码,代替下面的注释代码才可运行。
// for (nextPtr = next; nextPtr != NULL; nextPtr = next)
// {
// next = next-> next;
// delete [] nextPtr;
////delete nextPtr;
// }
}
template <class T>
inline
void* MemoryPool <T> ::alloc(size_t size)
{
if (!next)
expandTheFreeList();
MemoryPool <T> * head = next;
next = head-> next;
return head;
}
template <class T>
inline
void MemoryPool <T> ::free(void* doomed)
{
MemoryPool <T> * head = static_cast <MemoryPool <T> * > (doomed);
head-> next = next;
next = head;
}
template <class T>
inline
void MemoryPool <T> ::expandTheFreeList(int howMany)
{
size_t size = (sizeof (T) > sizeof (MemoryPool <T> *)) ?
sizeof (T) : sizeof (MemoryPool <T> *);
MemoryPool <T> * runner = static_cast <MemoryPool <T> * > ((void*)new char[size]);
next = runner;
for (int i = 0; i < howMany; i++)
{
runner-> next = static_cast <MemoryPool <T> * > ((void*)new char[size]);
runner = runner-> next;
}
runner-> next = 0;
}
#endif // MEMORYPOOL_H_
//Rational.h
#ifndef RATIONAL_H_
#define RATIONAL_H_
#include "MemoryPool.h "
class Rational
{
private:
int n;
int d;
static MemoryPool <Rational> * memPool;
public:
Rational(int a = 0, int b = 1) : n(a), d(b) {}
~Rational() {}
void* operator new(size_t size)
{
return memPool-> alloc(size);
}
void operator delete(void* doomed, size_t size)
{
memPool-> free(doomed);
}
static void newMemPool()
{
memPool = new MemoryPool <Rational> ;
}
static void deleteMemPool()
{
delete memPool;
}
};
#endif // RATIONAL_H_
//testRationalv2.cpp
#include <iostream>
#include <ctime>
#include "Rational.h "
using namespace std;
MemoryPool <Rational> * Rational::memPool = 0;
int main()
{
clock_t start, finish;
double dif;
Rational* array[1000];
Rational::newMemPool();
//计时开始
start = clock();
for (int j = 0; j < 500; j++)
{
for (int i = 0; i < 1000; i++)
{
array[i] = new Rational(i);
}
for (int i = 0; i < 1000; i++)
{
delete array[i];
}
}
//计时结束
finish = clock();
Rational::deleteMemPool();
dif = (double)(finish - start);
cout < < "processor time " < < dif < < endl;
system( "PAUSE ");
return 0;
}
问题处在MemoryPool的析构函数中,内存都是通过new[]申请得来的,书上的源代码也是用delete[]释放,但是却编译不成功,不信你可以试试,然而我改成delete释放却可以了,不知道产生了内存泄漏没有。
麻烦各位赐教。
[解决办法]
你申请的是只是char数组可以直接用delete释放
[解决办法]
MemoryPool <T> * runner = static_cast <MemoryPool <T> * > ((void*)new char[size]);
你说的是这个吧。你认为它是new []出来的。
那,你delete的时候,指针类型和new的时候相同吗?
delete [] (char *)XXX;
当然,于是你又漏了一个MemoryPool <T> * 的析构函数调用问题。
建议你先找 <Effective C++> 看一下重载new/delete的技术要点后,再研究这个。
效率和语法的直观/简洁是冲突的。建议你不要试图抠这一点点效率,几乎没有项目需要这一点点效率。
关于优化的建议就是:
第一:不要优化
第二:(仅供专家,)不要优化。
[解决办法]
唯一的关键就是你如何申请的,就如何释放。
所以应该象taodm所说,用 delete [] (char *)nextPtr; 就可以了。
至于因此没有调用析构函数,不必担心,因为你的for循环已经完成了所有内存的释放,无须再调析构函数了。
你改的那种用delete,其实是递归地调用析构函数,虽然每个都释放了,但是是按照MemoryPool <T> 的标准释放的,所以不能保证释放干净的。(如编译器内部用于保存new[]信息的部分没有释放)。因此,用new[],就一定用delete[],并且类型一致就好了。
至于说不要优化,不能认同这种观点。这是因噎废食,对于这种大规模使用堆内存的情况,不用内存池是不可想象的(要知道new在内核中运行,其运行时间是一个加法的1000倍,而最简单的栈分配只要一个加法就可以了,当你不得不大量使用堆时,你是忍受1000倍的速度损失,还是用可以分摊时间的内存池呢?)同时,这个问题和线程安全也没有关系,因为内存池也是用new/delete分配的。
一个前提是,必须知道,优化意味着难度和复杂度,可能比想象中更难,需要更全面地考虑问题。是否有必要付出这个代价呢?有必要时就要付出。
[解决办法]
Vitin(卫亭)同志已经表达的很明确了,没啥可补充的,呵呵。