If you are running code that makes calls to a native library in Java, what is the usual way of freeing memory allocated by these libraries when the memory allocation should
What you can do is use a Cleaner. This is a more official API in Java 9 but is available in Java 1.4+.
Essentially you give it a Runnable to execute when the resource is cleaned up.
One advantage of using a Cleaner is you can call it to clean up deterministically, but if you forget or fail to do so, the GC will call it after it runs.
There isn't a safe way to clean up an object when a thread dies as the Thread object can live for the life of the program even if dead. A simpler approach is to clean up as you know it is not needed or after the GC determines it is not required.
Another approach is to use a reference queue and a background thread. It's not as elegant but works across Java 8 and later versions.