【问题标题】:C++ Array size x86 and for x64C++ 数组大小 x86 和 x64
【发布时间】:2010-12-07 23:17:56
【问题描述】:

简单的问题,我正在编写一个需要打开巨大图像文件(8kx8k)的程序,但我对如何初始化巨大的数组以在 c++ 中保存图像有点困惑。

我一直在尝试这样的事情:

long long SIZE = 8092*8092;     ///8096*8096
double* array;
array = (double*) malloc(sizeof(double) * SIZE);
if (array == NULL)
{
    fprintf(stderr,"Could not allocate that much memory");
}

但有时我的 NULL 检查没有发现数组未初始化,知道为什么吗?

此外,即使在具有 12 GB RAM 的 x64 机器上运行,我也无法初始化超过 2 或 3 个数组,知道为什么吗?

我真的希望不必使用数组部分来代替。欢迎任何帮助。

谢谢。

【问题讨论】:

  • 如果您在 Windows 下,请查看地址窗口扩展:msdn.microsoft.com/en-us/library/aa366527(VS.85).aspx
  • 注意:malloc是C分配内存的方式,在C++中你应该使用new
  • 可能是一个错字,但仍然:“8k”应该是 8 * 1024,即 8192。“8096”读起来像是 4k (4096) 和 8k 的混合。
  • “数组未初始化”是什么意思? Malloc 不会初始化它分配的内存。你必须自己做。
  • Ups,是的,它是 8092,感谢 unwind 发现错误。当您在离开吃午饭之前急于发布问题时,就会发生这种情况。

标签: c++ arrays x86 64-bit dynamic-arrays


【解决方案1】:

您没有遇到数组大小问题。 8K*8K只有64M。即使是 64M 双打(sizeof==8)也不是问题;这将只需要 512 MB。现在,一个 32 位应用程序(无论它在哪里运行)应该能够分配其中的一些。不是 8,因为操作系统通常需要为自己保留一些空间(通常略高于 2GB),有时内存碎片化时甚至不需要 3。

“malloc failed but didn't return NULL”的行为是Linux配置错误,由# echo 2 > /proc/sys/vm/overcommit_memory修复

【讨论】:

  • 是的,每个阵列是 512 MB。最后我发现了错误,我正在使用 Visual Studio 2008 c++ 编译并在 x86 而不是 x64 中编译。虽然 vista 无法检查 NULL 很奇怪,但我想这也是 windows vista 中的一个错误。 :-/ --------几乎给了你正确的答案,但决定把它给digitalarbeiter,因为他提醒我不要一直把c和c++混在一起。无论如何,谢谢。
  • Vista 不需要检查,你可以。 Linux 错误实际上是一个错误,尽管分配内存失败,但 malloc 返回非 NULL 指针。这意味着即使是正确的程序也无法检查malloc 是否成功。
【解决方案2】:

malloc() 不初始化内存,它只是保留它。您必须明确初始化它,例如通过 string.h 中的 memset():

array = (double*) malloc(SIZE * sizeof(double));
if (array) memset(array, 0, SIZE * sizeof(double));

但是,在 C++ 中,您应该使用 new 而不是 ma​​lloc

double* array = new double[SIZE];
if (!array) {
    cerr << "Could not allocate that much memory" << endl;
}
for (int i=0; i<SIZE; i++) array[i] = 0.0;

关于大小:每个这样的数组是 512 MB。您确定需要双精度(这意味着图像具有 64 位像素深度)吗?也许一个浮点数就足够了?这将使内存占用量减半。

【讨论】:

  • 您有什么理由在 C 中使用 memset 并在 C++ 中使用循环吗?
  • 实际上,malloc 与使用数组一样多的 C++... // 然后你只需要捕获一个 std::bad_alloc
【解决方案3】:

如果您运行的是 32 位操作系统,您可能会遇到每进程 2GB 的地址空间限制。有几百 MB 的系统库和其他东西,以及 2 或 3 个 512MB 的阵列,很容易提供 2GB。一个 64 位操作系统可以帮助你。

【讨论】:

  • "...即使在具有 12 GB RAM 的 x64 机器上运行" -1
  • 硬件是否为 x64 无关紧要。如果操作系统是 32bit,每个进程的地址空间是 32bit,即使它使用 PAE 可能运行十几个 2GB 的进程,每个进程仍然被限制在它的 2GB 限制。
  • 他的系统有 12GB 内存,我敢打赌他已经在使用 64 位操作系统了。
  • 使用 64 位操作系统,您将获得 4Gb 限制。也应该使用 64 位编译器。
  • 是的,如果您也忘记在 x64 中编译,那么拥有 x64 机器是没有用的。 :-/哈哈
【解决方案4】:

您是将应用程序编译为 32 位应用程序(Visual Studio 中的默认应用程序,如果您使用的是该应用程序)还是 64 位应用程序?如果您将其构建为 64 位应用程序,您应该不会遇到麻烦。

malloc 分配(保留内存并返回一个指针),calloc 初始化(将所有零写入该内存)。

【讨论】:

    【解决方案5】:

    似乎您在 C 运行时堆中没有这种大小 (~500Mb) 的连续内存块。尝试将图像映射到进程地址空间,而不是将文件复制到内存中。您只能映射文件的必要部分。

    【讨论】:

      【解决方案6】:

      顺便说一句:尽管您不想打扰整个图像不会立即进入内存,但有理由不这样做。也许考虑一个抽象,允许您仅将当前需要的块保留在内存中。然后可以编写程序代码,就好像不知道内存问题一样。

      【讨论】:

        【解决方案7】:

        我真的希望不必使用数组部分来代替。欢迎任何帮助。

        您是否查看过内存映射文件?

        【讨论】:

          【解决方案8】:

          是的,听起来很像堆碎片,就像Kirill pointed out。另见:How to avoid heap fragmentation?

          【讨论】:

            【解决方案9】:

            我建议使用压缩。解压其中需要在代码中处理的部分,并在部分完成后对其进行压缩。

            第二个建议:编写代码来重载内存指针“operator+”和“operator-”,这样您就可以使用非连续内存缓冲区。使用较小的内存缓冲区使您的代码比连续较大的缓冲区更稳定。我经历过它并编写了一些运算符重载,请参阅http://code.google.com/p/effoaddon/source/browse/trunk/devel/effo/codebase/addons/mem/include/mcur_i.h 的示例。当我在 x86_64 上测试 47G malloc()ed 系统内存时,我每次 malloc() 调用只分配了 1G,所以我总共分配了 47 个内存块。编辑:虽然如果我尝试通过只使用一个 malloc() 来分配尽可能多的内存,但在 48G 系统上我只能获得 30G,比如不到 70%,这是因为每个 malloc() 请求的缓冲区更大,管理内存更多由系统/libc 本身消耗,你知道,我调用了 mlock() 来防止分配的内存被换出到磁盘。

            第三个:尝试posix文件映射,每个图像映射到内存。

            顺便说一句:虽然用 c++ 编写,但调用 malloc() 比 new() 更稳定,因为当内存紧张时,new() 容易引发异常而不是返回 NULL。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-03-14
              • 1970-01-01
              • 2011-12-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多