Skip to content

ByteBuffer extension ToByteArray makes temporary memory allocations #68

@alex3696

Description

@alex3696

https://github.com/anotherlab/UsbSerialForAndroid/blob/main/UsbSerialForAndroid/Extensions/BufferExtensions.cs

        public static byte[] ToByteArray(this ByteBuffer buffer)
        {
            IntPtr classHandle = JNIEnv.FindClass("java/nio/ByteBuffer");
            IntPtr methodId = JNIEnv.GetMethodID(classHandle, "array", "()[B");
            IntPtr resultHandle = JNIEnv.CallObjectMethod(buffer.Handle, methodId);

            byte[] result = JNIEnv.GetArray<byte>(resultHandle);

            JNIEnv.DeleteLocalRef(resultHandle);

            return result;
        }

byte[] result = JNIEnv.GetArray(resultHandle);
this line still makes temporary array allocations, not wrapping existing array
look to https://github.com/dotnet/android/blob/main/src/Mono.Android/Android.Runtime/JNIEnv.cs

		public static T[]? GetArray<T> (IntPtr array_ptr)
		{
			if (array_ptr == IntPtr.Zero)
				return null;

			if (typeof (T).IsValueType)
				AssertCompatibleArrayTypes (array_ptr, typeof (T[]));

			int cnt = _GetArrayLength (array_ptr);
			T[] ret = new T [cnt];
			CopyArray<T> (array_ptr, ret);
			return ret;
		}
  1. I didn't find a way to "display" arrays from java to .net
  2. I did not find a way to copy an array from a java array to .net array without using JNIEnv.GetArray (Java.Nio.ByteBuffer.Get this method does it in a similar way? didn't find implementation)
    if you know how to do this - this would be the basis of the solution.

But... android 9 introduce GetDirectBufferAddress
https://github.com/dotnet/android/blob/main/src/Mono.Android/Java.Nio/Buffer.cs
Now we can copy from the native raw pointer to .NET array, directly without memory allocations

        public static void CopyTo(this ByteBuffer buffer, int srcOffset, byte[] dstArr, int offset, int count)
        {
            ArgumentOutOfRangeException.ThrowIfGreaterThan(count, buffer.Capacity() - srcOffset);
            nint srcPtr = buffer.GetDirectBufferAddress();
            ArgumentOutOfRangeException.ThrowIfZero(srcPtr);
            srcPtr += srcOffset;
            Marshal.Copy(srcPtr, dstArr, offset, count);
        }

To do this, you need to initialize the buffer like this:
ByteBuffer bb = ByteBuffer.AllocateDirect(10);

what do you say?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions