I reach the next level of understanding how NSString::UTF8String works under the hood. If you are interested in how I get here, please read my previous post.
So, we need to know that despite NSString::UTF8String in apple doc noted as a property, it is a method. It creates Data with null-terminated cstring in it and then autorelease it. In one stack overflow thread, which I can not find now, I read that it creates new Data only if NSString contains characters outside ASCII. That would explain why UTF8String behavior differs from documentation most of the time, memory is not freed when NSString receives release message, but sometimes it actually works as expected. But my tests do not confirm this theory. So I still don't know why runtime sometimes frees memory.
Autorelease is a new concept for me. The idea is to have blocks, outside of which autoreleased memory is actually released. Every app that runs on macOS is wrapped in one of those blocks. And if you do not add one yourself, all autoreleased memory will be released at the end of the app. That was the actual reason for the memory leak I fought.
One more question is why NSString::UTF8String is slower than NSString::getCString? My benchmark shows 12.998us vs. 10.208us. Which in absolute numbers does not look like a big deal, but it is more than 20% which is huge. Here is the repo with test cases and benchmarks. If you know where this difference comes from or spot an error in the benchmark, please let me know.
I wish I knew how to write proper tests for memory leaks, but I still don't know. So, please, send help.