I wanted use ByteBuffer.allocateDirect
to keep data on native memory but it looks like it keeps data on heap.
I used this code to check that DirectByteBuffer
keeps data on heap.
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import java.nio.ByteBuffer
class MainActivity : AppCompatActivity() {
val tenMb = 10 * 1024 * 1024
val byteBuffer = ByteBuffer.allocateDirect(tenMb)
init {
if (byteBuffer.hasArray()) {
Log.i(TAG, "Byte buffer has heap array ${byteBuffer.array().size / 1024f / 1024f} MB")
} else {
Log.i(TAG, "Byte buffer doesn't have heap array")
}
}
companion object {
private const val TAG = "BYTE_BUFFER_TEST"
}
}
I got heap dump and saw that byte array with size 10 MB is kept on heap.
Image of heap dump
Also, I tried to allocate 300 MB to get OOM because a standard heap for Android app is 256 MB and I got it.
FATAL EXCEPTION: main
Process: com.android.myapplication, PID: 14976
java.lang.OutOfMemoryError: Failed to allocate a 314572819 byte allocation with 25165824 free bytes and 253MB until OOM, target footprint 27560064, growth limit 268435456
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at java.nio.DirectByteBuffer$MemoryRef.<init>(DirectByteBuffer.java:71)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:265)
at net.idrnd.test.myapplication.MainActivity.<init>(MainActivity.kt:10)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:44)
at android.app.Instrumentation.newActivity(Instrumentation.java:1441)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3839)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4126)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:108)
at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:195)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:157)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:90)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2544)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8501)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)
I have two questions:
- Why DirectByteBuffer keeps data on heap? I was sure that we use for this goal HeapByteBuffer and use DirectByteBuffer to keep data on native memory.
- How to keep data on native memory if DirectByteBuffer doesn’t work properly and I don’t want to use NDK?