3

I have problem with some application written under C++ Builder 6. After some time of running (week, month) the application crashes and closes without any error message. In my application log shortly before crash i get many "Out of memory" exceptions. I looked at the process when it was throwing out of memory exceptions (screenshot below) and it has lots of uncommitted private memory space. What can be a reason of such behavior?

I had such problem once, couple years ago. The reason for that was an option "use dynamic libraries" unchecked in linker options. When I checked it back the problem disappeared and vice versa. The test application which I made was just calling "new char[1000000]" and then delete. The memory was freed every time (no committed memory rise in windows task manager), but after some time I got out of memory, VMMap showed exactly the same thing. Lots of reserved private memory but most of it uncommitted.

Now the problem returned but I can't fix it the same way. I don't know if that was the reason but I had Builder 6 and 2010 istalled on the same machine. Now I just have Builder 6 and it seems that I cannot reproduce the error with test application like before. Ether way it seems that there is some memory manager error or something. CodeGuard doesn't show any memory leaks. When I create memory block with "new" it instantly shows in "memory commit size" and when delete the memory usage decreases, so I assume that the memory leaks are not the case, task manager doesn't show much "memory commit size".

Is there anything I can do? Is there any way I can release uncommitted memory? How to diagnose the problem any further?

The screenshot: https://i.stack.imgur.com/UKuTZ.jpg

manlio
  • 18,345
  • 14
  • 76
  • 126
Krzysiek
  • 185
  • 1
  • 10
  • Are you calling a Window API that returns allocated memory that you are not freeing, codeguard may not catch those. Codeguard is not infallible. – Gregor Brandt Feb 20 '13 at 04:35
  • The application has thousands of lines of code so there maybe some. For example playing waves through directsound i guess. But because of the size of the project and its dependency of various hardware devices connected to it (i'm very limited here), its quite hard to locate the problem. – Krzysiek Feb 21 '13 at 07:56
  • What concerns me is why it frees most of the space of reserved blocks and leaves some kb commited? Isn't that weird? There is huge count of 1.9MB blocks where just about 50KB is committed (the screenshot). Shouldn't it be committed if it wasn't freed, even if it was API allocation? – Krzysiek Feb 21 '13 at 08:03
  • One more thing. To the "Codeguard is not infallible". Yes I know, my assumption isn't just based on it, actually I hardly use it. The main problem I see is that the memory seems to be freed as the memory usage of the application doesn't ever rise so much. It's the application virtual memory ADDRESS SPACE that is being used of. Moreover I can't simulate such behavior myself anyhow, so I don't know what to look for. – Krzysiek Feb 21 '13 at 12:48
  • fairly old but still interesting question ... had to add some thing so look at my answer – Spektre Mar 04 '14 at 10:08

2 Answers2

3

I found a way to simulate this problem and solution.

for(int i=0; i<100; i++)
{
    char * b = new char[100000000];
    new char;
    delete b;
}

Borland memory manager reserves a block of memory which size is multiple of one page which is 4kB. When allocating memory size different than multiple of 4kB there is some free space which borland may use to allocate some other memory chunk. When the first chunk is deallocated the second is still keeping hole memory block reserved.

At first look the code should cause just 100B memory leak, but in fact it will cause memory allocation exception after less than 16 iterations.

I have found two solutions for this problem. One is FastMM, it works but also brings some troubles with it too. Second solution is to exchange borlndmm.dll with the one from Embarcadero Rad Studio 2010. I didn't test it thoroughly yet but it seems to work without any problem.

I should move the hole project to RAD 2010 but for some reasons I got stuck in Borland 6.

Krzysiek
  • 185
  • 1
  • 10
0

Prologue

Hmm interesting behaviour... I have to add some thing I learned the hard way. I dismiss BCB6 immediately after try it for few times because it had too much bugs for my taste (in comparison with BCB5 especially with AnsiStrings handling). So I stayed with BCB5 for a long time without any problems. I used it even for a very Big projects like CAD/CAM.

After few years pass I had to move to BDS2006 because of my employer and the problems start (some can be similar to yours). Aside the minor IDE and trace/breakpoint/codeguard bugs there are more important things like:

  1. memory manager

    • delete/delete[] corrupts memory manager if called twice for the same pointer without throwing any exception to notify ...
    • wrong default constructor/destructor for struct compiler bug was the biggest problem I had (in combination with the delete)
    • wrong or missing member functions in classes can cause multiple delete call !!! due t bug either in compiler or in C++ engine.

    but I was lucky and solve it here: bds 2006 C hidden memory manager conflicts (class new / delete[] vs. AnsiString)

  2. wrong compile

    Sometimes app is compiled wrongly, no error is thrown but some lines of code are missing in exe and/or are in different order then in source code. I saw this occasionally also in BCB 5,6. To solve that:

    1. delete all temp files like ~,obj,tds,map,exe,...
    2. close IDE and open it again just to be sure (sometimes view of local variables (mostly big arrays) corrupt IDE memory)
    3. compile again
  3. beware breakpoint/trace/codeguard behave differently then raw app

    especially with multi-threading App behaves different while traced and while not. Also codeguard do a big difference (and I do not mean the slow down of execution which corrupts sensitive timing). For example codeguard has a nasty habit of throwing out of memory exceptions without a reason sometimes so some parts of code must be checked over and over until it goes through sometimes even if the mem usage is still the same and far from out of mem.

  4. AnsiString operators

    There are two types of AnsiString in VCL normal and component property. So it is wise to take that into account because for component property AnsiString's are the operation of operators different. Try for example something like

    Edit1->Text+="xxx";
    

    also there are still AnsiString operator bugs like this:

    AnsiString version="aaa"+AnsiString("aaa")+"aaa";       // codeguard: array access violation
    
  5. Import older BCB projects

    Avoid direct import if possible it often creates some unknown allocation and memleaks errors. I am not sure why but I suspect that imported window classes are handled differently and the memleaks are related to bullet #1. Better way is create new App and create/copy components and code manually. I know it is backword but the only safe way to avoid problems still don't know where is the problem but simple *.bdsproj replacement will not help !!! And in *.dfm I had not seen anything suspicious.

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380