Help with strange memory behavior. Looking for leaks both in my brain and in my code-Collection of common programming errors
I have a non traditional technique to help find a suspected leak in code, that I’ve used countless times and it is very effective. Clearly it’s not the only or best way to find leaks, but it’s a trick you should have in your bag.
Depending the depth of your knowledge of the code, you may have a couple of suspect spots in mind. What I’ve done in the past is target those suspect spots by (what I call) amplifying the leak. This is done by simply putting a loop around a the suspect spot so it is called not once but many times, usually thousands, but that depends on the size of the underlying allocation. The trick is to know where to put the loop. Generally you want to move up the call stack to a spot where within the loop all allocated memory is expected to be deallocated. At run-time use perfmon to watch private bytes and working set, when it spikes you’ve found the leak. From that point you can narrow the scope of the loop down the call stack to zero in on the leak.
Consider the following example (lame as it may be):
char* leak()
{
char* buf = new char[2];
buf[0] = 'a';
buf[1] = '\0';
}
char* furtherGetResults()
{
return leak();
}
std::string getResults(const std::string& request)
{
return furtherGetResults();
}
bool processRequest(SOCKET client, const std::string& request)
{
std::string results;
results = getResults(request);
return send(client, results.c_str(), results.length(), 0) == results.length();
}
Its not always easy to find the leak if the code is distributed among separate modules or even in separate dlls. It also hard to find because the leaks is so small, but over time can grow large.
To start you can put the loop around the call getResults():
bool processRequest(SOCKET client, const std::string& request)
{
std::string results;
for (size_t i = 0; i < 1000000; i++) {
results = getResults(request);
}
return send(client, results.c_str(), results.length(), 0) == results.length();
}
If the memory usage spikes then you’ve got the leak, following this you move down the call stack to getResults(), then to furtherGetResults() and so on until you’ve nailed it. This example overly simplifies the technique but in production code there is typically a lot more code in each function called and it’s more difficult to narrow down.
This option may not always be available, but when it is it finds the problem very quickly.