你能给我一个内存泄漏的实际例子吗?

时间:2012-08-06 14:17:53

标签: c++ memory-leaks

我听说有很多内存泄漏漏洞,但我找不到内存泄漏的实际工作示例,你能否提供内存泄漏的实际工作示例,可能是一些大型开源项目并向我解释解决方案< / p>

THX。

10 个答案:

答案 0 :(得分:4)

实际上这很简单。在您的主要内容中:

char* c = new char[4];

然后退出。那是内存泄漏。 <{1}}之后没有new的任何delete都是泄密。

This answer有一些很好的例子,但正如我的评论所说的那样,找到一个外部观察者可以查看并轻松识别泄漏的已发布应用程序将非常困难。

答案 1 :(得分:3)

EDIT 正如詹姆斯所说,这是未定义的行为,没有承诺

你可以这样做:

#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类没有声明虚析构函数。

答案 2 :(得分:2)

这里可以给出很多例子。只需分配一些内存,不要释放它。

这方面的一个很好的例子如下:

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()抛出时,如果未捕获到异常,则永远不会执行delete[]。因此,内存泄漏。

这是应该使用智能指针的最好例子之一。


另一个例子是 - 一个函数,返回指向动态分配内存的指针。用户经常可能忘记释放这些记忆。类似的东西:

char* f()
{
    return new char[ 1024 ];
}

//... 

// in some other function
char* pSomething = f();

// do some stuff here and return

答案 3 :(得分:2)

想象一下,您正在处理网络数据并根据数据创建多态“消息对象”:

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对象可能选择将对象存储在某处并在以后再次使用它,如果没有人负责删除它,则会有完美的泄漏。

答案 4 :(得分:2)

虽然其他答案给出了足够的提示,但我在应用程序中看到了一些“真实世界”的内存泄漏。 我不记得这是在发布之前还是之后发现的,但是,我想这没关系。

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.

}

答案 5 :(得分:2)

我在我们(巨大的)遗留代码库中每天都在尖叫,诅咒和大吼大叫这样的代码:

// 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:保持意大利面条原样,用智能指针和newmake_shared替换所有make_unique资源,让编译器大喊大叫。当然,首先编写一个测试套件(之前不存在),以保证所有可能的输入集(未记录)的相同(通常是搞定的)行为。

答案 6 :(得分:0)

我在代码中经常遇到的一个例子是图像理解功能,其中分配了一个临时8位内存,并且从未发布(是的,我知道,当你做一个新的,之后立即删除...)

unsigned char* dataToBeUsed = new unsigned char[imgsize];
memcpy(dataToBeUsed, original, imgsize);
// use and process the data here

return value;

永远不会释放分配的内存 - &gt;内存泄漏。当应用程序完全退出时,Windows将终止内存,但在此之前,应用程序内存刚刚丢失 - &gt;泄漏。

答案 7 :(得分:0)

丢失指向动态分配内存的指针:

void foo()
{
   int *arr = new int[100];
}

答案 8 :(得分:0)

当程序员忘记释放分配的内存时发生内存泄漏时会发生内存泄漏: - )

linebuffer = new char[4096];
/* do things */
/* forget to free memory */

通常情况下,如果导致内存泄漏然后退出程序,则无害,因为操作系统通常会释放程序分配的资源。当您的应用程序运行很长一段时间(例如,服务)时会出现问题。如果你的程序导致内存泄漏,那么你将耗尽系统的内存,除非操作系统有机制来避免这种情况;在这种情况下,它将终止您的程序。

所以,小心吃鱼:这对记忆非常有益: - )

答案 9 :(得分:0)

为了给你一个真实的例子,在389 Directory Server(一个RedHat开源产品)中出现了一些谷歌搜索this memory leak