5

I'm simply running the following code in Borland C++ Builder Version 6;

for (int i = 0; i < 40000; i++)
{      
   try {
     __int64 n = 0;
     __int64 r = 1 / n;
   }
   catch (Exception& e) {}
}

and while running this loop, I see in task manager (Memory column) that it's leaking memory. Any idea why?

I was having memory leak while working on a calculating module in my project when I try to divide by zero and after hitting my head for many hours where is the memory leak, I realized that it's leaking memory in the above simple loop as well. No problem was found in the project.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
nommyravian
  • 1,316
  • 2
  • 12
  • 30
  • Is the problem with catching exceptions in general, or just catching that kind of exception? – David Heffernan Sep 18 '13 at 14:02
  • 3
    did you try to use some tools like valgrind? I don't think Task manager is a good tool to check memory leak – CS Pei Sep 18 '13 at 14:04
  • 3
    Integer division by zero yields undefined behaviour; it may leak as much memory as it wants. (And no exception is thrown per se, making the `try`/`catch` useless.) –  Sep 18 '13 at 14:04
  • 1
    @not-rightfold For this compiler, integer division by zero results in compiler defined behaviour. That behaviour is the raising of an exception. – David Heffernan Sep 18 '13 at 14:07
  • Are you sure you get a catchable exception? According to this http://stackoverflow.com/questions/6121623/catching-exception-divide-by-zero it should not be a catchable exception – RedX Sep 18 '13 at 14:08
  • @DavidHeffernan Hmm, I see. Still bad practice to rely on it, IMO. –  Sep 18 '13 at 14:08
  • @not-rightfold That's your opinion. Perhaps the asker doesn't want to write portable code following the standard. Which would be difficult anyway in this ancient and very non-standard compiler. – David Heffernan Sep 18 '13 at 14:09
  • I'm confused. Is `__int64` an object that allocates memory? Or does `Exception` leak? – Mats Petersson Sep 18 '13 at 14:49
  • 1
    @MatsPetersson `__int64` is like `int`. It will be allocated on the stack. No heap allocation. So surely the issue is with the exception. If indeed there is an issue. – David Heffernan Sep 18 '13 at 17:10
  • In this case, Borland's runtime raises an `EDivByZero` exception, which is allocated on the heap, and freed by the runtime when the `catch` block is done with it. – Remy Lebeau Sep 18 '13 at 20:49
  • The exception was catched in `Catch(Exception& e){}` block but not at `Catch(...){}`. The exception to catch div by 0 in borland is `EDivByZero` which I also used and it was caught but still leaking the memory. Trying `Catch(Exception& e){e.Free()}` worked and there was no memory leak but in the documentation it's forbidden to call `e.Free()` directly – nommyravian Sep 19 '13 at 09:01
  • It is not just forbidden to call Free(), but it is also forbidden to free a caught exception. You do not own that memory, the RTL does. You have no business freeing it manually. – Remy Lebeau Sep 19 '13 at 15:10
  • but if RTL isn't freeing it, won't we be looking at VCL source code to know the reason? I tested with FASTMM as well, it's doing same. – nommyravian Sep 19 '13 at 15:27

2 Answers2

4

From the standard 5/4 we learn that:

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.

So since division by zero is not mathematically defined, the behavior is undefined. Undefined behavior includes memory leaks, so it's not really worthwhile to speculate further on why it's leaking memory (although a tool like valgrind might be able to help you identify a source).

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 3
    Valgrind doesn't run on Windows. And the compiler in question does not adhere to the standard. The question does not ask about the standard. The question very specifically asks about one specific compiler. For the compiler in question the result of integer division by 0 is the raising of an exception. – David Heffernan Sep 18 '13 at 14:22
  • @David, you are right because it seems the problem of VCL (Visual Component Library) because calling e.Free in exception block solved the problem but it's forbidden to call e.Free directly. I'm going to check source code for VCL to check the behavior. – nommyravian Sep 19 '13 at 08:31
2

Task Manager is not a good tool to use for testing memory leaks. It can only report how much memory has been allocated by a process, but not how that process uses the memory.

What you are not taking into account is that C++Builder's memory manager caches freed memory, it does not return it to the OS right away. What you are likely seeing is memory fragmentation, not memory leaking. Fragmentation can prevent the memory manager from reusing memory it has already cached, making it allocate more and more OS memory. That would cause the behavior you are seeing in Task Manager. If you watch Task Manager's Page Faults column, you will see that value rising along with the memory usage. That is a good indication that memory is not being reused.

With that said, the default memory manager used by C++Builder 6 was not the greatest memory manager. It was replaced in a later version by FastMM, which is also usable in C++Builder 6. FastMM does not suffer from memory fragmentation.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I checked the increasing count in Page Faults which, according to you, tells about reusable memory. I downloaded teh `FastMM` and installed following http://www.realthinclient.com/sdkarchive/index12e8.html?cmd=viewtopic&topic_id=10&section_id=15&sid= but I can still see memory leakage (or fragmentation) in the task manager. – nommyravian Sep 19 '13 at 09:39
  • As I mentioned in the comments above that Catch(Exception& e){e.Free()} worked for me and it stoped showing the increasing memory usage by the program in task manager but it's forbidden calling e.Free() directly. Why e.Free() changes the behavior? How would you define that? Thanks. – nommyravian Sep 19 '13 at 09:41
  • and one more thing, with the default memory manager, when I use e.Free in the catch block, Memory column in task manager stays unchanged but Page Faults are still increasing (not as fast as was without e.Free()) – nommyravian Sep 19 '13 at 09:52
  • One of the benefits of using FastMM is that it has memory leak reporting. Upon app shutdown, it can generate a report that tells you exactly what memory has been leaked, the call stack leading up to the memory being allocated, and even what type of class the memory represents (if a class is being leaked). – Remy Lebeau Sep 19 '13 at 15:14