5

Background: I'm writing some code which serializes and deserializes a binary protocol across a network, and I'm writing C#, Swift and Java client code.

We get a packet off the network (Byte array), deserialize it into a tree of structures, and then traverse the tree looking for stuff.

In C#, I made use of the Span<T> struct which gives you a "view" onto an existing memory buffer. Likewise in Swift, I used the Data struct which can also act like a "view". In C++ I'd probably use some similar concept.

Essentially something like:

raw buffer: R_T1aaa_T2bbb_T3ccc.
parses as Root -> [Tag1[aaa],Tag2[bbb], Tag3[ccc]]

In the above model, the Root,Tag1,Tag2,Tag3 objects are structs allocated on the stack. The tag contents (aaa, bbb, ccc) are just pointers into the underlying raw buffer and we haven't allocated or copied any heap memory for them at all.

In Java, I had begun by creating a class like this (@MarkRotteveel kindly points out that I could use ByteBuffer rather than making my own wrapper class):

class ByteArrayView {
    @NonNull final byte[] owner; // shared
    final int offset;
    final int length;
}

I was going to proceed with the same pattern as used in C#, Swift, however the thought occurred to me - I'm using array views to avoid heap allocation, however everything in Java is a heap allocation. Instead of copying some byte[] values around the place, I allocate ByteArrayView objects, but it's heap-allocations nonetheless.

I'm aware that if I had large "slices" then something like my ByteArrayView or java.nio.ByteBuffer would reduce the total amount of memory that my program allocations, but for the most part my tags are small - e.g. 4 bytes, 12 bytes, 32 bytes.

Does trading small byte[] objects for wrapper objects have any meaningful result if they're all still on the heap? Does it actually make things worse because there's an additional indirection before we get to the actual bytes that we want to read? Is it worth the extra code complexity?

What would experienced Java developers do here?

Orion Edwards
  • 121,657
  • 64
  • 239
  • 328
  • Pardon my ignorance, but what is `ByteArrayView` ? Is it a class? If yes, then is it part of the JDK ? – Abra May 18 '20 at 11:12
  • 1
    Why not use a `ByteBuffer` for this (though I haven't checked carefully if that would entirely fit your usecase)? – Mark Rotteveel May 18 '20 at 11:31
  • @Abra ByteArrayView is a class I just made up. That's the entirety of it right there – Orion Edwards May 18 '20 at 11:36
  • @MarkRotteveel thanks! I hadn't considered ByteBuffer - I'm only a java dev maybe 5% of the time so my knowledge of the API's isn't super deep. It looks basically perfect, and I won't need to write my own ByteArrayView now. I think the question still stands though - If I have 10 heap-allocated ByteBuffers is that really any better than 10 small heap-allocated byte[]s ? – Orion Edwards May 18 '20 at 11:38
  • 1
    I would guess that using these types of views for relatively small source byte arrays will produce more overhead than just allocating objects with the necessary data directly. That might be different if the array is huge and the slices were dozens or more bytes each. You might want to look at questions with regard to sizes of objects, eg [In Java, what is the best way to determine the size of an object?](https://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object) – Mark Rotteveel May 18 '20 at 11:45

0 Answers0