That's a good summary of how each tool accomplishes different needs. I've also used arenas in conjunction with cleaners, where a Kotlin object allocates memory via the arena and clears the arena in the cleaner.
My project is a KMP bindings library, with the goal of maintaining a consistent KMP API, without requiring specific native memory management primitives. I've found I can accomplish this in the native C platforms with careful usage of Kotlin objects to bind the lifecycle of underlying native memory. As Landry mentioned, you have to be careful that the Kotlin object is retained properly for the underlying native memory lifecycle, as when the Kotlin object is GCed, the cleaner will release the native memory. I've been able to avoid the need to expose memory clear methods in the API though.