malloc and free aren't overhead.
If I'm reading a file, then opening and closing a file is not overhead either. But if I'm reading a file and some convoluted system in my own process is slapping some 3000% extra work on top because it needs to asynchronously track opened files and close them at arbitrary time later - that is overhead and creates bugs.
Which is one reason why many GC languages end up with bad emulations of an almost overhead free pattern like "try-with-resources" in Java and "IDisposable" in C# etc.