有没有办法确定free()是否会失败?

时间:2009-11-07 14:59:09

标签: linux free malloc shared-memory

有没有办法确定free()如果调用某个内存块指针会失败?

我遇到以下情况:有权访问共享资源的线程 可能处于释放所述资源的状态。现在我需要设计一种安全的方法来清理这个共享资源。

当然,我已经为正常案件分配了资源的所有权,但上述限制案例呢?

更新:如果我使用其他同步机制,则只需要进行更多清理,可能涉及其他限制条件。如果可能的话,我想限制/避免这些。

决议:我最终决定进行重新分解。感谢所有贡献者。你们摇滚!

4 个答案:

答案 0 :(得分:6)

我已经看过各种尝试,包括这一次:

void m_free(void **p)
{
        if (*p != NULL) {
                free(*p);
                *p = NULL;
        }
}

解除引用类型惩罚指针不仅打破了各种平台,“插入这个示例”只有在初始化,释放和重新初始化每个现有函数(包含已编译的库)中的每个指针时才能工作,并且可以使用C库也是如此。

然后,处理优化和锁定免费线程安全问题。 BAH!

简而言之,如果你无法跟踪你在一个函数中分配的内容,那么它是时候重新考虑这个函数了。做得那么......你会发现对更安全的免费()的需求很快消失了。如果在其支持的平台上工作,Valgrind是您的朋友。根据你的标签,它确实是你的朋友:)

或者,自费使用malloc() that sports garbage collection,具体取决于您如何分配内容并完全摆脱free()。之后,调试变得几乎终极有趣。

希望你能重新考虑?虽然您似乎也存在互相排斥的问题,但它只会导致重新分解。即,让free()之前的行阻塞,或者在尝试获取锁时失败..并且在具有锁的线程中将释放的指针设置为NULL,至少在您实现的结构中是这样。

答案 1 :(得分:2)

我不相信有一个符合你想要的符合标准的界面。

但是,我可以想到一些技巧。您可以让容易出错的线程直接调用free()而不是free()的包装器;包装器可以保存地址或最后几个地址,以便您可以确定块是否已被释放。您还可以阻止信号,建立关键部分,或处理可能中断*线程的任何其他内容。

更新:在退出/清理之前,死亡线程是否会释放此内存?我经常为不需要在稳定状态下释放的内存编写malloc前端(作为速度优化)。如果线程只是自行设置,你可以在线程启动之前对内存进行malloc操作,并让线程调用前端,只传递动态块的未链接,不可用的部分。它将运行得更快,然后当线程死亡时,您可以立即释放整个块。这里的一般想法是让容易出故障的线程通过调用可以在事后清理的服务来获取其内存。

另一个想法是:每线程堆如何?如果可以说服线程只在它们的生命周期内从它们自己的堆中分配所需的内存,那么当线程重新加入父节点时,这将很好地组织清理任务以释放整个线程堆。

答案 2 :(得分:1)

我认为没有办法完全按照你的要求去做。

问题在于无法确定死亡线程在死亡时所处的状态。它只是调用free()并且不再进一步了吗? free()是否将块添加回空闲列表?你无法分辨。


如果线程以这种方式死亡是一个非常罕见的条件(因此可以将未使用的内存留下 - 你只是想知道不使用它),那么以下(使用Windows调用)释放内存并且'标记'它对你的其他线程是免费的:

void* ptr;
...
void* desiredPtr = ptr;
if(InterlockedCompareExchangePointer(&ptr, NULL, desiredPtr) == desiredPtr)
  free(desiredPtr);

这样做是为了确保只有一个线程试图释放内存,在此之前它将地址设置为NULL,因此没有其他线程会尝试释放()它。


如果将内存保持在周围是不可接受的,那么最好的方法可能是拥有一个单独的线程,其唯一的工作就是释放内存。然后,其他线程可以排队对free-memory-thread的空闲请求。由于自由内存线程非常简单,因此永远不会死,并且可以正常完成自由操作。

答案 3 :(得分:0)

如果您使用有效指针调用free,我看不出它会如何失败。如果失败,则必须是由于指针无效。

除了同步对共享内存的访问权限(例如,使用mutex)之外,还必须明确所有权以避免双重释放等情况。双重释放是指两个或多个线程具有有效指针,但随后多个线程尝试释放内存。尽管第二个线程具有非空指针,但它不再有效。

如果您在C / C ++中遇到内存问题,可以尝试使用HeapAgent这样的内存库。像这样的内存库将检测并初始化每个内存分配。在释放内存之前,它会先检查内存指针是否有效,并且没有缓冲区溢出错误。应该没有代码更改,因为它可以简单地替换内置的malloc / free。此外,该库可以帮助查找内存泄漏,覆盖和无效引用。

解决问题的另一个策略可能是将资源清理集中到一个线程。当一个线程完成资源时,它只是标记它可以被垃圾收集器线程清理。

当然,那就是Plan C - 使用Java ......开个玩笑。