听说有很多内存泄漏漏洞,但是我找不到内存泄漏的实际工作示例,您能否提供一个内存泄漏的实际工作示例,可能是一些大型开源项目并解释解决方案给我
谢谢。
其实很简单。在您的主要内容中:
char* c = new char[4];
然后退出。那是内存泄漏。任何new
不被跟踪的delete
都是泄漏。
这个答案有一些很好的例子,但就像我的评论所说的那样,很难找到一个外部观察者可以查看并轻松识别的带有泄漏的已发布应用程序。
我每天都在为我们(巨大的)遗留代码库中的这样的代码尖叫、诅咒和大喊:
// returns raw pointer with changing conventions who's the owner...
HelpFoo* Foo::GetFoo(Bar* pBar, OtherFoo* pFoo)
{
// all 'local' variables even those allocated on freestore declared
// and initialized in a large block at the beginning of the function/method
HelpFoo *A = new HelpFoo;
OtherHelpFoo *B, *C;
EvenMore *D = new EvenMore;
// and so on, these blocks can be huge...
// a complicated spaghetti code in here, with dozens of nested 'ifs'
if (/* some expression */) {
} else if (/* some other expression */) {
// and so on... then suddenly:
if (/* some other nested expression */) {
// I forgot that I've allocated other memory at the beginning...
return A;
}
}
// some miserably written logic here and suddenly
if (D) delete D; return A;
// call to some other function with cryptical name without any
// kind of knowledge what happens with the resource:
FooTakesReferenceToPointer(&A);
// suddenly returning something completely different
// what should I free, A, D...?
return C;
}
我试图在评论中写出问题所在。显然,忘记例外。意大利面条代码太糟糕了,没有人能说出实际的逻辑是什么。因此,忘记释放内存真的非常容易,而且这种情况非常非常频繁地发生。解决方案1:丢弃并重写所有内容。解决方案 2:保持原样,new
用智能指针和make_shared
or替换所有 ed 资源make_unique
,让编译器大喊大叫。当然,首先编写一个测试套件(以前不存在)以保证所有可能的输入集(未记录)的相同(通常是搞砸的)行为。
编辑正如詹姆斯所说,这是未定义的行为,所以没有承诺
你可以这样做:
#include <vector>
class Base
{
public:
Base()
{
baseData = new char [1024];
}
~Base()
{
delete [] baseData;
}
private:
char* baseData;
};
class Derived : public Base
{
public:
Derived()
{
derivedData = new char[1024];
}
~Derived()
{
delete [] derivedData;
}
private:
char* derivedData;
};
int main()
{
std::vector<Base*> datablocks;
datablocks.push_back(new Base());
datablocks.push_back(new Derived());
for(unsigned int i = 0; i < datablocks.size(); ++i)
{
delete datablocks[i];
}
datablocks.clear();
return 0;
}
Derived 类中的数据不会在此处删除,因为我们在 Base* 上调用 delete 并且 Base 类没有声明虚拟析构函数。
这里可以举出很多例子。只需分配一些内存,不要释放它。
一个很好的例子如下:
char* pBuffer = new char[ 1024 ]; // or something else, dynamically allocated
// do something here
// now suppose, calling f() throws
f();
// do some other things
delete[] pBuffer;
当f()
throws 时,如果异常没有被捕获,delete[]
将永远不会被执行。因此,内存泄漏。
这是应该使用智能指针的最佳示例之一。
另一个例子是 - 一个函数,返回指向动态分配内存的指针。用户通常可能会忘记释放该内存。就像是:
字符
char* f()
{
return new char[ 1024 ];
}
//...
// in some other function
char* pSomething = f();
// do some stuff here and return
虽然其他答案给出了足够的提示,但我在我们的应用程序中看到了一些“真实世界”的内存泄漏。我不记得这是在发布之前还是之后发现的,但是,我想这并不重要。
void f()
{
BYTE* b = NULL;
f = open a file;
while (!f.end())
{
int size = getNextRecordSize(f);
b = new BYTE;
readNextRecord(f,b);
process record;
}
delete b;
}
很难检测到这一点。审阅者可能会理所当然地认为通过看到删除调用正确删除了内存。但是,它只删除为最后一条记录分配的内存。休息被泄露。
class A
{
public:
BYTE* get()
{
allocate a new buffer, copy the someData buffer and return that.
The client is expected to delete it
};
private:
BYTE* someData;
};
void f()
{
A a;
B.initialize(a.get()); // It is so convenient to use the pointer. It is not obvious from the function name
// that the result of get has to be deleted.
}
想象一下,您正在处理网络数据并根据数据创建多态“消息对象”:
while (true)
{
char buf[1024];
size_t len = read_from_network(buf, 1024); // fictitious, for demonstration only
Message * p = Message::Parse(buf, len); // allocates new, dynamic, concrete object
engine.process(p);
}
对象可能会选择将engine
对象存储在某个地方并稍后再次使用它,如果没有人负责删除它,那么您就有了完美的泄漏。
只需丢失指向动态分配内存的指针:
void foo()
{
int *arr = new int[100];
}
给你一个真实的例子,在 389 Directory Server(一个 RedHat 开源产品)中搜索一下这个内存泄漏。
我经常在我们的代码中遇到的一个例子是图像理解函数,其中分配了一个临时的 8 位内存,并且永远不会释放(是的,我知道,当你做一个新的,然后做一个删除......)
unsigned char* dataToBeUsed = new unsigned char[imgsize];
memcpy(dataToBeUsed, original, imgsize);
// use and process the data here
return value;
分配的内存永远不会释放 -> 内存泄漏。当应用程序完全退出时,Windows 将杀死内存,但在此之前,在应用程序中内存刚刚丢失-> 泄漏。
当程序员因忘记释放分配的内存而发生内存泄漏时,就会发生内存泄漏:-)
linebuffer = new char[4096];
/* do things */
/* forget to free memory */
通常,如果您导致内存泄漏然后退出程序,这并没有什么害处,因为操作系统通常会释放程序分配的资源。当您的应用程序运行很长时间(例如,服务)时,就会出现问题。如果您的程序导致内存泄漏,那么您将耗尽系统的内存,除非操作系统有避免这种情况的机制;在这种情况下,它将终止您的程序。
所以,小心吃鱼:这对记忆很有好处:-)