5

I am running a C++ program, which dies with std::bad_alloc at arbitrary points, which depend on the input specified. Here are some observations/points about the program:

  • for shorter runs (the running time depends on the input), the program completes normally. The problem comes only for larger runs.
  • the program does not have any detectable memory leaks. This was checked with Valgrind/Memcheck for smaller runs. Moreover, my entire code does not have any pointers (all dynamic allocations are done by the libraries, e.g., in std::vector and std::string; it is the allocation inside these library classes which fails), so memory leaks are extremely unlikely.
  • several objects are allocated in loops and then moved to containers. Several of these objects are intended to be alive until almost the end of the program.
  • I suspected heap fragmentation could be an issue (see C++ program dies with std::bad_alloc, BUT valgrind reports no memory leaks) but I am on a 64-bit system with a 64-bit compiler (specifically Linux with g++) and Heap fragmentation in 64 bit land leads me to believe heap fragmentation cannot be an issue on 64-bit systems.

Is there anything else I should try? Any particular tools that could help? Any other suggestions?

UPDATE: It finally turned out that the virtual memory had been limited through ulimit -v earlier. I forgot about this later, and hence had memory exhaustion. Setting it back to unlimited fixed the problem.

Community
  • 1
  • 1
r.v
  • 4,697
  • 6
  • 35
  • 57
  • Check for basic stack corruption, buffer overflows or bad returns. These are things valgrind would miss and could cause corruption issues. – Jesus Ramos Aug 18 '13 at 21:12
  • Agreed, I could not do much on that part. Do you have any tools in mind that I could try? – r.v Aug 18 '13 at 21:14
  • I usually do it by hand, easy way to get some clues is to load it in gdb and walk back up the stack once it hits bad_alloc and check what is the junk value and where it's possibly coming from – Jesus Ramos Aug 18 '13 at 21:17

2 Answers2

6

std::bad_alloc means that you have requested more memory than there is available.

You can have situations where a program has no leak, but still genuinely runs out of memory:

vector<long> v;
long n = 0;
for(;;)
{
   v.push_back(n++);
}

will eventually exhaust all available memory in whatever machine you have - but it's not leaking - all memory is accounted for in the vector. Obviously, ANY container can be made to do the exact same thing, vector, list, map, doesn't really matter.

Valgrind only finds instances where you "abandon" allocations, not where you are filling the system with currently reachable memory.

What LIKELY is happening is a slower form of the above - you are storing more and more in some container. It may be something you are caching, or something you are not removing when you thought you had removed it.

Watching the amount of memory on the application is actually using in some montioring program ("top" in Linux/Unix, "task manager" in Windows) and seeing if it actually grows. If that is the case, then you need to figure out what is growing - for a large program, that can be tricky (and some things perhaps SHOULD grow, others don't...)

It is of course also possible that you suddenly get some bad calculation, e.g. asking for a negative number of elements in T* p = new T[elements]; would cause bad alloc, since elements is converted to an unsigned, and negative unsigned numbers are HUGE.

If you can catch the bad_alloc in a debugger, that sort of thing is usually pretty easy to spot, because the large amount requested by new will be quite obvious.

Catching the exception in the debugger should in general help, although it is of course possible that you are just allocating memory for a small string when it goes wrong, if you do have something that leaks, it's not unusual that this is what is allocating when it goes wrong.

If you are using a flavour of Unix, you could also, to speed up the error-finding, set the amount of memory the application is allowed to use to smaller size, using ulimit -m size (in kilobytes) or ulimit -v size.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Thanks! The problem was a bit naive one. A few days back I had limited the virtual memory to around 4GB (through `ulimit -v` -- your answer reminded me!). Now, I was running this program in the same terminal, forgetting this setting and hence the issue. Setting it back to unlimited made things right. As I had said in the question, being on a 64-bit system and not using pointers means the other issues you point out are unlikely. Perhaps this question and answer will help others in the future though! – r.v Aug 18 '13 at 21:39
  • If you are not using pointers [indirectly, through for example `std::vector`, possibly], you wouldn't get `std::bad_alloc`]. Are you sure that using more than 4GB is correct for your application - I'm not saying it ISN'T, I'm just asking to make sure you have thought about it. Increasing memory to allow the application to complete is fine if you understand why it's using more memory. I had a nasty bug many years ago that turned out to be a slow leak - we increased memory, and it ran fine for 24 hours. The speeded it up a bit, and all of a sudden it started running out within 24 hours... – Mats Petersson Aug 18 '13 at 21:43
  • The calculations I am doing are going to be memory-intensive but it is very likely I can bring down the memory utilization to some extent. I am going to investigate that in the near future once the code is feature-complete. – r.v Aug 18 '13 at 21:49
1

std::bad_alloc may possibly also mean that you are requesting a negative amount of data, even when there is enough memory in the machine.

This case happens easily on my 64-bit linux machine when I use a regular signed int (which is still 32-bit) instead of a long int (64 bits) to specify an array count, and I multiply two numbers that are too large in order to get the final count. The results of the multiplication quietly overflow at 2.147Gig and thus can turn negative.

Say for example you want to allocate 100 million points in a 21-dimensional space. No problem. Count is 2,100,000,000. Now increase the dimension size to 22, and it falls off a cliff. This is easy to verify with printf's:

int N = 100000000;
int D = 22;
int count = N * D;
printf("count = %'d\n", count);

gives

count = -2,094,967,296

and the std::bad_alloc kicks in because the requested memory count is negative.

Ed.: I note in comments this seems to be an irreproducible result, as now new[count] is giving std::bad_array_new_length after rebooting the machine. That is, the code still is incorrect and breaks, but the error message given is different than before. Don't do this in either case.

DragonLord
  • 6,395
  • 4
  • 36
  • 38
  • Actually it is now looking like this exact case gives `std::bad_array_new_length`. Sigh. – DragonLord Dec 04 '19 at 22:17
  • Apparently new[N*D] may have been actually running out of swap space because there were way too many other processes running on the computer. **Rebooting** into a clean machine seems to have fixed this. YMMV. – DragonLord Dec 04 '19 at 22:24