Following the debug for yesterday’s problem I decided to spend some time to analyse the memory behaviour of feng with valgrind, and I noticed a few interesting things. The main one is that there are quite a few places where memory is allocated but is never ever freed, because it’s used from a given point till the end of the execution.
Since memory gets deallocated when the process exits; adding explicit code to free that type of resources is not necessary; on the other hand, it’s often suggested as one of the best practises in development since leaks are never a good thing, code may be reused in different situations where freeing the resource is actually needed, and most importantly: not freeing resources will sidetrack software like valgrind that is supposed to tell you where the leaks are, which either forces you to reduce the level of detail (like hiding all the still-reachable memory) or to cope with false positives.
With valgrind, the straightforward solution is to use a suppression file to hide what is known to be false positives; on the other hand, this solution is not extremely practical: it is valgrind specific, yet valgrind is not the only software doing this; it does not tell you if you were, for any reason, fiddling with pointers during the course of the program, and it separates the knowledge about the program from the program itself, which is almost never a good thing.
Now of course one could just always free all the resources; the overhead of doing that is likely minimal when it comes to complex software, because a few calls to the
free() functions and friends are probably just a small percentage of the whole code of the software; but still if they are unnecessary there is no real reason to have them compiled in the final code. My approach is perhaps a bit more hacky, but I think it’s a nice enough approach: final memory cleanup is done under preprocessor conditional, checking for the
NDEBUG preprocessor macro, the same macro that is used to disable assertions.
In a few places, though, I’ve been using the
GOnce constructor (more or less equivalent to pthread_once) that allows me to execute initialisation when actually needed instead of having initialisation and cleanup functions to call from the
main function. While this works pretty well, it makes it tricky to know when to actually free resources. Luckily most modern compilers support the
destructor attribute, which basically is a way to say that a given function, that can very well be static, should be called before closing down. Relying on these destructors for actual program logic is not a very good idea because they are not really well supported, but for leak testing and debugging they can be quite useful instrumentation.
I’ll try to provide more detailed data once I make feng not report leaks any longer.