8

我想在我的基于 Windows 的软件中渲染 400 万个三角形,该软件是用 Visual Studio C++ 2010(以发布模式构建)编写的。当我渲染 390 万个三角形时,软件消耗的总 RAM 内存为 400MB。但是当我尝试渲染 400 万个三角形(仅多出 100K)时,系统给了我一个错误。

For Example:
Point *P = new (std::nothrow) Point[nb_triangles]; //==> "(std::nothrow)" is for catching the run time memory allocation error. (Point is X, Y, Z floats)
If(P == NULL)
   message("System can't allocate this much memory.");  // System gives me this error. It means the system can't reserve huge memory for this operation.

我必须为顶点、面法线、顶点法线等分配内存。

实际上我没有得到的是,我有 8 GB RAM 内存,(但在 32 位 XP windows = 3.2GB 内存),软件只保留 400MB,可用内存超过 1 GB,但是当我尝试再渲染 100K 三角形,它给了我一个错误。为什么它给我一个错误?因为它仍然有超过 1 GB 的可用 RAM 内存?

无论如何要解决这个问题,我怎样才能为我的应用程序分配所有可用内存?因为这个问题,我不得不在软件中做一个限制,只为渲染 390 万个三角形,这并不好。

我心中的另一个问题是,用于内存分配的 c++“new”运算符给了我错误,那么 c“malloc”运算符呢?“malloc”可以解决这个问题,这两者之间有什么区别吗?

请指导我。谢谢。

更新#1:

我已经尝试了很多,修改代码,消除内存泄漏等,但我无法分配超过400万的内存。不可能将我的整个代码更改为“向量”。我不能变成“向量”,我现在必须用“新”来坚持我自己的数据结构。以下是我要分配以呈现 1 个对象的指针。

P = new points[10000000]; // points is the class with 3 floats X, Y, Z;
N = new Norm[10000000]; // Norm is the class with 3 floats X, Y, Z;
V = new vNorm[10000000]; // vNorm is the class with 3 floats X, Y, Z;
T = new Tri[10000000]; // Tri is the class with 3 integers v1, v2, v3;
4

4 回答 4

14

这是 Windows 编程的一大神话,一个进程永远不会耗尽 RAM。Windows 是一个按需分页的虚拟内存操作系统,如果一个进程需要更多的 RAM,那么操作系统会通过分页出其他进程拥有的其他内存页面来腾出空间。或者进程本身,交换一段时间未使用的页面。

任务管理器以默认设置报告进程的内存使用情况的方式鼓励了这个神话。它显示工作集,即 RAM 中进程的实际字节数。该值通常远小于进程分配的虚拟内存量。当一个进程无法再分配虚拟内存时,它会在 OOM 上死掉。Taskmgr 中的另一个统计数据,VM 大小值。它通常不是因为所有的虚拟机都被使用了,而是因为没有一个足够大的洞。SysInternals 的 VMMap 实用程序是查看进程如何使用其地址空间的好方法。

获得更大的虚拟内存地址空间需要进行相当基本的检修。尽管今天很容易,但只需将 x64 定位为平台目标。64 位进程有大量可用的地址空间,仅受页面文件最大大小的限制。只要您可以使用 /LARGEADDRESSAWARE 链接器选项在 64 位操作系统上实际运行,您就可以在 32 位模式下跛行。这会将 64 位操作系统上的 VM 大小从 2 GB 增加到 4 GB。

于 2013-03-25T02:10:54.073 回答
2

对于其中一个问题:

is there any diffirence between these two?

new 和 malloc 的区别如下:

  1. malloc在 C 中使用,malloc分配未初始化的内存。分配的内存必须用free.

  2. new通过调用相应的构造函数来初始化分配的内存。分配的内存new应该被释放delete(调用析构函数)。您无需提供内存块的大小即可释放分配的内存。

并不清楚是否newmalloc是否按照标准相关(这取决于具体的编译器是否实现newusing malloc),因此问题可能通过简单地替换newmalloc.

从您显示的代码中,很难发现错误的原因。您可以尝试将动态数组替换为vector,看看它是否能解决您的问题。同时,您可以valgrind检查您的代码中是否存在内存泄漏(如果您可以使用 makefile 将您的代码移植到 Linux,因为不幸的是 valgrind 在 Windows 上不可用。)。

于 2013-03-25T02:00:18.263 回答
2

我心中的另一个问题是,用于内存分配的 c++“new”运算符给了我 >error,那么 c“malloc”运算符呢?“malloc”可以解决这个问题吗,这两者之间有什么区别吗?

malloc和之间有区别new,例如,new会初始化你的内存并自动调用类的构造函数。或者如果它们是原始类型(例如float,intchar)则进行初始化。new此外,应使用delete调用析构函数的关键字删除分配的内存。

Cmalloc()以及newVisual Studio 中的运算符在内部调用HeapAlloc(). 如果所需的内存太大或在进程之间共享,则HeapAlloc()调用。VirtualAlloc()因此,它不一定能解决您的问题。事实上,如果您使用 C++,请坚持使用new.

于 2013-03-25T02:03:38.217 回答
0
P = new points[10000000]; // points is the class with 3 floats X, Y, Z;
N = new Norm[10000000]; // Norm is the class with 3 floats X, Y, Z;
V = new vNorm[10000000]; // vNorm is the class with 3 floats X, Y, Z;
T = new Tri[10000000]; // Tri is the class with 3 integers v1, v2, v3;

这段代码分配了 30M 个向量,每个向量包含 3 个浮点数,因此是 30M * 3 * 4 = 360MB 的数据,加上每个 3 个整数的 10M 向量,10M * 3 * 2 = 60MB 的数据。

这通常应该工作。为了向自己证明它有效,您应该将此代码放在一个独立的项目中。你必须从有效的开始。它确实有效。去尝试一下:

// main.cpp

struct Vector3 { float x, y, z; }
struct Tri { int v1, v2, v3; }

int main() {
  const int N = 10000000;
  new Vector3[N]; // no need to assign to variables in this simple test
  new Vector3[N];
  new Vector3[N];
  new Tri[N];
  // At this point, all four arrays are dynamically allocated although
  // inaccessible as we don't have any variables to work with. That's fine
  // for what we want to show: that the allocations do succeed. If they won't,
  // the code will "crash", i.e. abort via std::terminate.

  // No need to deallocate - it's a waste of time. The process is exiting,
  // the memory will be freed no matter what you do at this point. The OS
  // is taking over
}

如果您的系统上有 > 2GB 的 RAM,它会正常工作。我确实在虚拟机中尝试了 Windows XP SP 6(32 位),并使用了稍微更新的 MSVC(2017)。MSVC 版本在这方面不会有太大的不同,除非 MSVC 2010 中存在一些可怕的错误(我认为像 array new 这样基本的东西不会被严重破坏)。

如图所示,new 从不返回 nullptr!如果new返回,则返回一个有效值。如果分配失败,它不会返回,所以没有问题。

怎么不回来?它抛出一个异常,并且程序以错误指示终止,因为该异常将在未处理的情况下传播。

不可能将我的整个代码更改为“向量”

嗯?这是相当微不足道的。向量可以像 C 样式数组一样被索引,因此使用向量的代码将保持不变。

就是这样:

// main.cpp
#include <algorithm>
#include <vector>
#define CPP20 (__cplusplus > 201703L)
#if CPP20
#  include <ranges>
#endif

struct Vector3 { float x, y, z; }
struct Tri { int v1, v2, v3; }

int main() {
  const int N = 10000000;
  auto P = std::vector<Vector3>(N);
  auto N = std::vector<Vector3>(N);
  auto V = std::vector<Vector3>(N);
  auto T = std::vector<Tri>(N);

  // awful C code as an example
  for (int i = 0; i < N; ++i)
    N[i] = P[i];

  // more idiomatic C++ code
  std::copy(P.begin(), P.end(), N.begin());

  // even more idiomatic on C++20
  #if CPP20
  std::ranges::copy(P, N);
  #endif

  // KISS code
  P = N; // you can't do that with raw C arrays!

  // C++20 KISS with superpowers
  std::ranges::copy(P | std::views::reverse, N)
}
于 2021-07-01T05:40:00.803 回答