【问题标题】:std::vector reserve method fails to allocate enough memorystd::vector 保留方法未能分配足够的内存
【发布时间】:2010-12-30 02:18:19
【问题描述】:

我的 C++ 应用程序中有一个缓冲区类,如下所示:

class Buffer
{
    public:
    Buffer(size_t res): _rpos(0), _wpos(0)
    {
        _storage.reserve(res);
    }

    protected:
    size_t _rpos, _wpos;
    std::vector<uint8> _storage;
}

有时使用构造函数会失败,因为它无法分配所需的内存空间。例如,有一次,使用res = 37 调用构造函数导致了一个段错误,我从其核心转储中获得了以下堆栈跟踪:

#0  0x00007f916a176ed5 in raise () from /lib/libc.so.6
No symbol table info available.
#1  0x00007f916a1783f3 in abort () from /lib/libc.so.6
No symbol table info available.
#2  0x00007f916a1b33a8 in ?? () from /lib/libc.so.6
No symbol table info available.
#3  0x00007f916a1b8948 in ?? () from /lib/libc.so.6
No symbol table info available.
#4  0x00007f916a1bb17c in ?? () from /lib/libc.so.6
No symbol table info available.
#5  0x00007f916a1bca78 in malloc () from /lib/libc.so.6
No symbol table info available.
#6  0x00007f916ac0c16d in operator new (sz=37)
    at ../../.././libstdc++-v3/libsupc++/new_op.cc:52
        p = <value optimized out>
#7  0x00000000004e3d11 in std::vector<unsigned char, std::allocator<unsigned char> >::reserve (this=0x7f911bc49cc0, __n=31077)
    at /usr/local/lib/gcc/x86_64-unknown-linux-gnu/4.4.2/../../../../include/c++/4.4.2/ext/new_allocator.h:89
        __old_size = 0
        __tmp = <value optimized out>

我使用 GCC 4.4.2 作为 64 位应用程序编译了这个应用程序,我在 Debian 5 x64 中使用它。

非常感谢任何帮助。 谢谢

【问题讨论】:

  • 跟踪明确显示 res = 31077,而不是您声称的 37。它仍然很小(至少对于 64 位系统),但您可能在错误的地方寻找故障。你能从回溯中显示第 8 帧及以上的帧吗?

标签: c++ linux memory-management segmentation-fault stdvector


【解决方案1】:

因为段错误在 malloc 中,很可能有其他代码破坏了堆(即写入到它们不拥有的内存部分,并且正被堆管理器使用)。

我建议使用Valgrind 来查找正在破坏堆的代码。

【讨论】:

  • 我不能在这个应用程序中使用 Valgrind,因为它是一个服务器应用程序并且负载很重。 Valgrind 让它变得如此缓慢,以至于它几乎变得毫无用处。结果,段错误永远不会发生。不幸的是,我需要 Valgrind 以外的解决方案来找到原因。也许我可以在应用程序中实现一些东西来为我找到原因。
  • @Martin York:如果你没有注意到,我正在尝试通过请其他人指导我找出我的错误来学习编写没有任何错误的代码。
  • 如果您没有注意到,Martin York 只是指导您找出错误。 ;) 在另一台机器上运行 valgrind。最终,您没有太多选择。在此过程中某处,一些代码以某种方式破坏了堆,并且在此段错误发生之前的某个时间。正如 Martin York 所说,您只有两个选择:1) 编写不包含此类错误的代码,或 2) 运行诊断工具如 Valgrind 以帮助您找到存在的错误.
【解决方案2】:

如果由于负载过重而无法使用 Valgrind 找出内存损坏的位置,您仍然可以使用较轻的解决方案进行测试。

对于 Valgrind 不适用的服务器应用程序(因为平台在 Solaris 8 上),我使用 mpatrol (http://mpatrol.sf.net) 获得了不错的结果,尤其是 dmalloc (http://dmalloc.com)。

在某种程度上,您可以在不重新编译的情况下使用它们(只需重新链接 dmalloc,预加载 mpatrol 的库)。他们将替换内存原语以对内存使用执行额外检查(这些原语的错误参数,读取一个,堆损坏,......)其中一些检查将在问题发生时准确触发,而其他检查将比实际的错误代码稍晚触发。通过调整启用的检查以及检查频率(如果适用),您可以在执行基本检查的同时几乎全速运行。

我建议使用 dmalloc 重新编译以获得所谓的“FUNC_CHECK”,对我来说,这增加了错误发现的准确性,而性能成本可以忽略不计。

【讨论】:

    猜你喜欢
    • 2018-10-23
    • 2023-04-05
    • 1970-01-01
    • 2020-05-26
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-04
    相关资源
    最近更新 更多