【问题标题】:Recursive deallocation of larger tries较大尝试的递归释放
【发布时间】:2020-05-28 15:01:24
【问题描述】:

我已经编写了一个基本函数,用于在 C 中递归地释放 trie 数据结构:

// Root pointer is passed as arg in initial call
void destroy(node *trav)
{
    for (int i = 0; i < N; i++)
    {
        if (trav->children[i])
        {
            destroy(trav->children[i]);
        }
    }

    free(trav);
}

这个函数似乎在任何较小的字典文件中都能正常工作。程序成功加载和卸载的最大文件包含 134,480 个单词。

但是,在释放较大的 trie 时会产生分段错误。导致分段错误的较大文件包含 506,915 个单词。

Valgrind 产生的错误信息指出:“Invalid read of size 8”后跟几个回溯,最后; “地址没有被堆栈、malloc 或(最近)释放”。

这可能是什么原因?

【问题讨论】:

    标签: recursion memory memory-management segmentation-fault trie


    【解决方案1】:

    这可能是什么原因?

    堆栈溢出可能会导致这种情况,尽管这似乎不太可能:几乎没有局部变量,因此每帧可能只消耗 32 字节的堆栈,这将允许递归 8M/32 == 262144 级深度与 Linux 默认8MiB 堆栈。

    但是,如果你的 trie 极度不平衡,堆栈溢出是可能的。

    您可以尝试ulimit -s unlimited 看看是否可以解决问题。

    或者您可以在 GDB 下运行您的程序,并检查报告 SIGSEGV 的指令。如果是CALLPUSH或者其他形式的“移入栈”,也很有可能发生栈溢出。

    【讨论】:

    • 我的资源限制已设置为最大值。如何使用 GDB 来识别分段错误的原因?它只是说当我通过 GDB 运行程序时收到信号 SIGSEGV。
    • @GabrielSaul gdb --args /path/to/exe arg1 ...。您可能还想阅读sourceware.org/gdb/onlinedocs/gdb/index.html 的介绍——它会很好地为您服务。
    • 非常抱歉。事实证明,我的一个缓冲区变量不足以处理某个字符串。不过感谢您的资源!
    • @GabrielSaul 您应该考虑使用地址清理程序 (github.com/google/sanitizers/wiki/AddressSanitizer) 构建您的程序——这可能不是此类唯一错误,即使它原来,使用-fsanitize=address 进行测试是一个非常好的习惯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    相关资源
    最近更新 更多