仅使用 600 MB 内存时,调整 QByteArray 的大小会引发 std::bad_alloc

Posted

技术标签:

【中文标题】仅使用 600 MB 内存时,调整 QByteArray 的大小会引发 std::bad_alloc【英文标题】:Resizing QByteArray throws std::bad_alloc when only using 600 MB of memory 【发布时间】:2013-06-21 23:18:33 【问题描述】:

我是 Qt 新手,需要加载和处理一些大文件。相反,我的内存不足。以下代码说明了我的问题:

QByteArray mem;
for(int i=1; i<=20; ++i)

    std::cout << "eating " << (i * 100) << "MB";
    mem.resize(i * 100 * 1024 * 1024);

当 std::bad_alloc 达到 600MB 时,我得到了它。那真的不应该发生。 是否有增加堆大小的秘密开关?

我在 Windows 上使用 Qt 5.0.2 和 Visual C++ 10.0 x86 编译器。

【问题讨论】:

【参考方案1】:

AFAIK QByteArray 分配一个连续的内存块。虽然您的应用程序可能仍有大量可用的虚拟内存,但很有可能分配给您的数组的当前内存块无法进一步扩展,因为您的内存管理器没有足够大的连续块。

如果您需要处理一些大文件,而不是分配内存并将它们以一个块的形式加载到内存中,我建议您查看将“视口”映射到文件中的内存并以这种方式处理它。根据文件的大小,您很可能能够将整个文件内存映射到一个块中的内存中。这在 Windows 上也比逐字节加载文件更有效,因为它利用虚拟内存系统在相关文件中分页。

【讨论】:

+1 基本上是对的,但是我使用的库需要内存中的整个文件。我主要对分配失败的原因感兴趣: 您是否需要内存中的特定数据结构中的文件,或者您需要一个指向文件开头的指针和一个指向文件结尾的指针,两者都指向“内存”位置?大不同。【参考方案2】:

在 Windows 上,32 位进程可以有 2 GB 的堆内存。如果此内存不包含足够大的连续块来处理您的 Bytearray,您将遇到错误分配异常。

MSVC 知道 /LARGEADDRESSAWARE (Handle Large Addresses) 和 /HEAP (Set Heap Size) 链接器选项。

您可以检查这些更改是否会影响您一次可以分配的字节数。

在我的 x64 机器上,在 MSVC2012 上使用 /MACHINE:X86 编译的可执行文件会针对 >=1200MB 的单个分配引发错误的分配异常。

如果我将/LARGEADDRESSAWARE 添加到链接器命令行,程序将继续运行,直到在eating 2100MB 之后崩溃。

如果我改用 /MACHINE:X64 进行编译,该进程会毫无例外地将块分配到 8000MB(可能更多,但我只测试到 8GB)。

【讨论】:

好答案。我不知道 /LARGEADDRESSAWARE 选项。 不过,我很惊讶我遇到了相对较小的分配问题。从 500MB 调整到 600MB 意味着我在内存中有一个 500MB 的块,需要一个 600MB 的块。在 2GB 堆中听起来可行。碎片化不会那么糟糕……但我想你一定是对的。无论如何,我没有理由不使用 x64。 我没有看过 QByteArray 的实现,但是如果它对内存块进行就地扩展,即使是最小的碎片也会导致问题。 您从哪里获得 MSVC 12?那是某种预发布版本吗? 11 刚出来...

以上是关于仅使用 600 MB 内存时,调整 QByteArray 的大小会引发 std::bad_alloc的主要内容,如果未能解决你的问题,请参考以下文章

[Node] 内存溢出与 old-space 大小调整

问题下载大 blob 文件 (600mb+)

SSMS 中的网格控制

当我将屏幕调整为小于 600 像素时,媒体查询不起作用

PHP GD 允许的内存大小已用尽

虚拟内存是啥东西?有啥用?如果虚拟内存不足会有啥危害?如何调整虚拟内存的大小?