Archived Forum Post

Index of archived forum posts

Question:

Memory Leak in Chilkat C++?

Aug 21 '17 at 12:10

See code below. If run it like this, 10 leaks. If I comment out the entire IF section, 0 leaks. Ideas?

CkCrypt2 crypt;
if (!crypt.UnlockComponent("hello"))
{
  m_dwErrorCode = -1;
  m_strErrorText = A2T(crypt.lastErrorText());
  return _T("");
}


Answer

This should explain what you see: https://www.chilkatsoft.com/p/p_109.asp

#define _CRTDBG_MAP_ALLOC
#include "stdafx.h"
#include <stdio .h>
#include <crtdbg .h>
#include "CkSettings.h"
#include "CkXml.h"

void TestLoadXml(void)
    {
    CkXml xml;
    xml.LoadXmlFile("crisp.xml");
    xml.SaveXml("out.xml");
    }

// Many C++ developers incorrectly think there are memory leaks
// in the Chilkat C++ libraries.  This is not the case.
// For performance reasons Chilkat C++ classes *may* utilize internal
// structures in memory that are built/initialized once and re-used
// during subsequent method calls.  Calling CkSettings::cleanupMemory
// deallocates these structures.  However, once cleanupMemory is called,
// no other Chilkat methods can be called, including object destructors.
// The cleanupMemory method is provided for those programmers that wish
// to check for memory leaks.
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    TestLoadXml();

// Only necessary if checking for memory leaks.
    // Only call just before exiting the program.

// In this example you will notice that if cleanupMemory
    // is commented out, it will appear as if there are memory leaks.
    // If you call cleanupMemory, you will see that there are no leaks.
    // In fact, if you write a "for" loop an call TestLoadXml 100,000 times,
    // you will see that memory usage does not steadily increase.  This is
    // because the internal structures that may be created are created once
    // and re-used.
    CkSettings::cleanupMemory();

_CrtDumpMemoryLeaks();

return 0;
}

Answer

Thanks for the article. I’m a bit confused... If I comment out the “cleanupMemory” and it shows that there are memory leaks doesn’t that mean that the library isn’t cleaning up its allocated memory correctly? Am I supposed to be calling “cleanupMemory” on program exit? I thought that would be taken care of in the destructor for each class.


Answer

No, the memory that isn't getting cleaned up has to do with things that are built once and stay resident. For example, compression huffman encoding tables, or character encoding translation tables, as well as other things. The cleanupMemory is provided to deallocate those build-once/stay-resident memory structures just in case you want to check for memory leaks. You don't have to call it. When a program exits, it does not matter if heap memory remains that was not deallocated -- by virtue of the fact that the process is exiting means that the entirety of the process's memory is deallocated by the OS.


Answer

Gotcha. This is kind of going against all my non-automatic-garbage-cleanup-C++ instincts, though... Heap memory, memory allocated via new or malloc, is dynamically allocated and needs to be de-allocated, via delete or free respectively, before program termination. Stack memory, memory allocated at compile time, is cleaned up by the compiler automatically. If you’re allocating the memory on the heap it would need to explicitly be cleaned up or that memory is leaked. Even if they’re globally used between classes, if that memory is dynamically allocated there needs to be clean up. To go back to your example, if you make a class 1 time or 100,000 times you get the same memory leaks reported. That just means it’s one copy of the memory that’s leaking but it’s still a leak...

Does that sound legit? I’ve been doing this for a really long time so things may have changed faster than my understanding but I’m pretty sure heap memory is still not automatically collected...


Answer

You're not thinking it quite right. The heap is not something that exists outside the process. When a process exits, all of the memory used by the process is no longer used. The heap is part of the process, just like the stack, the executable code, etc. (There can actually be many heaps within a process, but all of them are contained within the process.)

The "leak" you are seeing has to do with certain computational tasks that can be performed once, and then kept in memory so they don't have to be constantly re-computed. Without this feature, there could be dramatic performance degradation for various features.

For example, after you create the first instance of CkCrypt2, you might see the "leak". But then if you write a loop to create/delete new instances a million times, you'll find there is no buildup of leaks. The memory does not continually increase. This is because it's a one-time (singleton) instance of something internal, perhaps a lookup table, that is computed once when 1st needed.

The cleanupMemory function only exists to help a programmer with cleaning up memory before a program exits to help for the case when he/she might be debugging memory leaks. Actual leaks are important to prevent as a program is running. You don't want actual unintended leaks to accumulate while a program is running. You'll eventually run out of memory. If, however, you have an intentional "leak" that is a build-once table or structure, it really makes no difference whether that memory is deallocated before a program exits.

Think of the heap as a container owned by the process. At program exit, it doesn't matter if something is left within the container because the entire container is thrown out. When a process exits, the entire amount of memory associated with the process is gone -- stack, heap, executable code that resides in memory, etc.