我正在维护一个遗留的C++应用程序,它似乎存在缓慢的内存泄漏。我已经通过确保当前配置不再抛出任何异常来“修复”内存泄漏,并且我还可以触发泄漏并通过配置它来扩展它以导致许多异常。
所有分配的内存都是使用alloca()而不是malloc()完成的。我对此的解释是,这是因为alloca()像java垃圾收集器一样工作,并在退出上下文时自动释放内存。
由于泄漏非常明显地绑定到抛出的异常,所以我的理论是,当抛出异常时,alloca()无法释放内存。
这有道理吗?如果是这样的话,我认为它是alloca()中的一个主要缺陷,但是当我google alloca()时,这似乎是一个问题。
我很感谢你对任何专家的见解。
发布于 2018-12-14 10:43:44
这个问题很可能是由于某种程度的间接影响造成的。
字面上的问题是“如果抛出异常,alloca是否返回内存?”。答案是:它只返回--直接分配的内存--。不运行析构函数,alloca-allocated内存中的任何拥有指针都会泄漏。
发布于 2018-12-14 10:15:07
在C++中,您不应该使用C内存管理例程。在现代C++中,智能指针为您提供了细粒度的确定性垃圾收集。
尽管通过alloca()分配的空间可能有例外情况下被取消分配(因为通常是通过增加当前堆栈帧的大小来完成的)。这不是标准的一部分,因此我认为你不能保证。
但是--这也意味着对象上的任何适当的析构函数都不会被调用。这意味着,如果对象执行自己的内存管理,这将不会被清除(因为析构函数不会运行来清理它)。
尽管alloca()可能非常快。我认为它为内存管理增加的额外负担(在一般情况下)是不值得的;尽管如果您特别需要额外的速度,它可能是值得的。
代码如下所示:
void func()
{
MyType* x = (MyType*)alloca(sizeof(MyType));
passXtoCFunctionThatDoesNotTakeOwnership(x);
}应该写成这样:
void func()
{
std::unique_ptr<MyType> x = std::make_unique<MyType>();
passXtoCFunctionThatDoesNotTakeOwnership(x.get());
}如果您使用它来保存一个对象数组。
void func()
{
MyType* x = (MyType*)alloca(sizeof(MyType) * arraySize);
// STUFF
x[0].stuff();
}那么最好使用std::载体。
void func()
{
std::vector<MyType> x;
x.reserve(arraySize); // or resize() if that is appropriate
// STUFF
x[0].stuff();
}如果您将它用于简单的对象。那么,您可能应该声明自动变量:
void func()
{
MyType* x = (MyType*)alloca(sizeof(MyType));
x->myData = 5;
}您应该声明一个变量:
void func()
{
MyType x;
x.myData = 5;
}发布于 2018-12-14 10:15:49
来自Linux 男人
…… 因为由alloca()分配的空间是在堆栈帧中分配的,所以如果函数返回的被一个对longjmp(3)或siglongjmp(3)的调用跳过,那么这个空间就会自动释放。 …… 内联代码通常由一条调整堆栈指针的指令组成,不检查堆栈溢出。因此,不存在空错误返回。 . Bugs如果不能扩展堆栈帧,则没有错误指示。(但是,在分配失败后,如果程序试图访问未分配的空间,它很可能接收到一个SIGSEGV信号。)在许多系统中,alloca()不能在函数调用的参数列表中使用,因为由alloca()保留的堆栈空间将出现在函数参数空间的中间。
这样,异常不会导致堆栈帧中由alloca分配的内存发生泄漏。但是,与任何异常一样,这可能导致堆内存泄漏,因为将跳过放置在alloca之后的析构函数和内存释放方法。
https://stackoverflow.com/questions/53777376
复制相似问题