我想在基于Windows的软件中渲染4百万个三角形,该软件是用Visual Studio C ++ 2010(在发布模式下构建)编写的。当我渲染3.9百万个三角形时,软件消耗的总RAM内存为400MB。但是当我尝试渲染4百万个三角形(仅多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:
我已经尝试了很多,修改了代码,删除了内存泄漏等,但我无法分配超过4百万的内存。它不可能将我的整个代码更改为“向量”。我不能改成“向量”,我现在必须用“新”来坚持我自己的数据结构。 以下是我想分配以呈现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;
答案 0 :(得分:12)
这是Windows编程的重大神话之一,一个进程可以从不耗尽RAM。 Windows是一个需求分页的虚拟内存操作系统,如果一个进程需要更多的RAM,那么操作系统会通过分页其他进程所拥有的其他内存页来腾出空间。或者流程本身,将页面交换出来但已经使用了一段时间。
任务管理器使用默认设置报告进程的内存使用情况的方式鼓励了这一神话。它显示工作集,即RAM中进程的实际字节数。一个值通常远小于该进程分配的虚拟内存量。当OOM不能再分配虚拟内存时,进程就会在OOM上消失。 Taskmgr中的另一个统计信息,VM大小值。它通常不会因为使用了所有虚拟机而死亡,但因为没有留下足够大的漏洞。 SysInternals' VMMap实用程序是查看进程如何使用其地址空间的好方法。
获得更大的虚拟内存地址空间需要进行相当彻底的改革。虽然今天很容易,但只需将x64作为平台目标。 64位进程具有大量可用的地址空间,仅受页面文件的最大大小限制。通过使用/ LARGEADDRESSAWARE链接器选项,只要您可以指望实际在64位操作系统上运行,您就可以在32位模式下跛行。这样可以在64位操作系统上将VM大小从2 GB增加到4 GB。
答案 1 :(得分:2)
其中一个问题:
is there any diffirence between these two?
new和malloc之间的区别如下:
malloc
用于C,malloc
分配未初始化的内存。分配的内存必须与free
一起发布。
new
通过调用相应的构造函数来初始化已分配的内存。分配有new
的内存应与delete
(调用析构函数)一起发布。您不需要给出内存块的大小以释放分配的内存。
目前尚不清楚new
和malloc
是否根据标准相关(取决于特定编译器是否使用new
实现malloc
),因此只需将new
替换为malloc
即可解决问题,也可能无法解决问题。
从您显示的代码中,很难发现错误原因。您可以尝试用vector
替换动态数组以查看它是否可以解决您的问题。同时,您可以使用valgrind
检查代码中是否有内存泄漏(如果您可以通过makefile将代码移植到Linux,因为很遗憾,Windows上没有valgrind。)。
答案 2 :(得分:2)
在我的脑海中还有一个问题是,用于内存分配的c ++“new”运算符给我>错误,c“malloc”运算符怎么样?可以“malloc”解决这个问题,这两者之间是否有任何差异>
malloc
和new
之间存在差异,例如,new
会初始化您的内存并自动调用类的构造函数。或者初始化它们是否是原始类型(例如float
,int
,char
等)。此外,应使用调用析构函数的new
关键字删除delete
分配的内存。
C的malloc()
以及Visual Studio中的new
运算符在内部调用HeapAlloc()
。 HeapAlloc()
如果所需内存太大或在进程之间共享,则调用VirtualAlloc()
。因此,它不一定能解决您的问题。事实上,如果你使用C ++坚持使用new
。
答案 3 :(得分: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,它会正常工作。我确实在虚拟机中尝试了 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)
}