maxpayne
maxpayne

Reputation: 1111

How can I allocate all the availble memory in visual studio for my application?

I want to render 4 millions triangles in my windows based software which is written in Visual Studio C++ 2010 (Build in Release Mode). When I render 3.9 millions triangles, the total RAM memory consumed by the software is 400MB. But when I try to render 4 millions triangles (just 100K more), the system gives me an error.

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.

I have to allocate memory for vertices, face normals, vertex normals, etc.

Actually what I am not getting is, I have 8 GB RAM memory, (but in 32 bit XP windows = 3.2GB memory), and the software is just reserved 400MB, the free memory is more than 1 GB, but when I try to render just 100K triangles more, it gives me an error. Why it is giving me an error? because it still has more than 1 GB free RAM memory?

Is there anyway to fix this issue, how can I allocate all the available memory for my application ? Because of this issue, I have to make a limit in the software just for rendering 3.9 millions triangles and it is not good.

And one more question in my mind is, c++ "new" operator for memory allocation giving me error, how about c "malloc" operator ? can "malloc" fix this issue, is there any diffirence between these two?

Please guide me. Thanks.

Update # 1:

I have tried a lot, modify the code, remove memory leaks, etc, but I can not allocate memory more than 4 millions. Its not possible to change my whole code into "vector". I can't change into "vector", I have to stuck on my own data structure now with "new". Following are the pointers that I want to allocate in order to render 1 object.

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;

Upvotes: 8

Views: 16419

Answers (4)

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;

This code allocates 30M vectors of 3 floats each, so that's 30M * 3 * 4 = 360MB of data, plus the 10M vectors of 3 integers each, 10M * 3 * 2 = 60MB of data.

That generally should work. And to prove to yourself that it works, you should put this code in a stand alone project. You must start from what works. And it works indeed. Just try it:

// 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
}

It'll work fine if you have > 2GB of RAM on your system. I did try on Windows XP SP 6 (32 bit), in a VM, with a slightly newer MSVC (2017). The MSVC version won't make much difference in that respect, barring some horrible bug in MSVC 2010 (something as fundamental as array new wouldn't be so badly broken, I don't think).

As shown, new never returns nullptr! If new returns, it returns a valid value. If it fails to allocate, it won't return, so no problem there.

How does it not return? It throws an exception, and the program terminates with an error indication, since that exception will propagate unhandled.

Its not possible to change my whole code into "vector"

Huh? It's fairly trivial. The vectors can be indexed just as C-style arrays, so the code that uses the vectors will remain the same.

Here's how:

// 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)
}

Upvotes: 0

Aniket Inge
Aniket Inge

Reputation: 25733

And one more question in my mind is, c++ "new" operator for memory allocation giving me >error, how about c "malloc" operator ? can "malloc" fix this issue, is there any diffirence >between these two?

There are differences between malloc and new, for example, new will initialize your memory and call the constructor of the class automatically. Or initialize if they are primitive types(such as float, int, char etc). Also the memory allocated by new should be deleted with the delete keyword which calls the destructor.

C's malloc() as well as new operator in Visual Studio internally call HeapAlloc(). HeapAlloc() calls VirtualAlloc() if the memory required is too large, or is shared between processes. So, it will not necessarily fix your issue. Infact if you are using C++ stick to using new.

Upvotes: 2

taocp
taocp

Reputation: 23664

For one of the questions:

is there any diffirence between these two?

the different between new and malloc is as follows:

  1. malloc is used in C, malloc allocates uninitialized memory. The allocated memory has to be released with free.

  2. new initializes the allocated memory by calling the corresponding constructor. Memory allocated with new should be released with delete (which calls the destructor). You don't need to give the size of memory block in order to release the allocated memory.

It is not clear whether new and malloc are related according to the standard (it depends on whether a specific compiler implements new using malloc or not), so the issue may or may not be resolved by simply replacing new with malloc.

From the code you showed, it is difficult to spot the cause of error. You may try to replace the dynamic array with vector to see if it solves your problem. Meanwhile, you may use valgrind to check whether you have memory leak in your code (if you can somehow port your code to Linux with makefiles since unfortunately valgrind is not available on Windows.).

Upvotes: 2

Hans Passant
Hans Passant

Reputation: 942518

It is one of the Great Myths of Windows programming, a process can never run out of RAM. Windows is a demand-paged virtual memory operating system, if a process needs more RAM then the operating system makes room by paging out other memory pages, owned by other processes. Or the process itself, swapping pages out that haven't been used for a while.

That myth is encouraged by the way Task Manager reports memory usage for a process with its default settings. It shows working set, the actual number of bytes of the process that are in RAM. A value that's usually much smaller than the amount of virtual memory allocated by the process. A process dies on OOM when it can't allocate virtual memory anymore. Another statistic in Taskmgr, the VM size value. And it usually dies not because all VM was used but because there isn't a hole left that's big enough. The SysInternals' VMMap utility is a good way to see how a process uses its address space.

Getting a larger virtual memory address space requires a pretty fundamental overhaul. Albeit that it is easy today, just target x64 as the platform target. A 64-bit process has massive amounts of address space available, limited only by the maximum size of the paging file. You could limp along in 32-bit mode, as long as you can count on actually running on a 64-bit operating system, by using the /LARGEADDRESSAWARE linker option. Which increases the VM size from 2 GB to 4 GB on a 64-bit operating system.

Upvotes: 16

Related Questions