It's not necessary, but I think it's easier to not make a special case
of main(); the rules for creating well-written code are easier to
remember if they don't have more special cases than they have to.
Sometimes, explicitly freeing memory requires added complexity in order
to keep track of what needs to be freed. E.g. if you have linked data
structures where you could have multiple pointers to a single block of
memory, you have to take steps to avoid multiple free()s of a single
block. Similarly if pointers can be to either static or dynamic data.
Adding such complexity is especially pointless if it only comes into play
upon termination, e.g. if you have complex structures which must exist in
order for the program to perform its normal function.
Also, there's always the possibility that code from main() may someday
get moved off to another function; if that code already contains
properly connected malloc() and free() calls, that's one less thing to
worry about during the move.
If the structure of the code is such that "pairing" malloc and free makes
sense, I'll do it. But in that case, I may set __free_hook (glibc) or
similar to point to an empty function once termination is assured. This
also deals with external libraries which typically have to free()
everything upon finalisation to be on the safe side.
Meticulously free()ing memory when you know that the program is about to
terminate is like rearranging the deckchairs as the Titanic is sinking.
Such operations can often take far longer than is immediately apparent, as
you often end up walking through memory which has long since been swapped
out.