This discussion is archived
6 Replies Latest reply: Apr 18, 2013 12:56 PM by 1003050 RSS

ByteBuffer's static "wrap" method -- managing memory

1003050 Newbie
Currently Being Moderated
Hello,

I have a function which will be called many, many times over:

     public static ByteBuffer byteArr2ByteBuff(byte[] data, int off, int len) {
          byte[] subData = new byte[len];
          try {
               System.arraycopy(data, off, subData, 0, len);
          } catch (Exception e) {
               e.printStackTrace();
          }
          // TODO find out if null'ing out subData works? Curious if this helps efficiency? This function will get called a LOT...
          ByteBuffer out = ByteBuffer.wrap(subData);
          subData = null;
          return out;
     }

My question this:

At the end of my code, I null out the "subData" array manually since I am not sure if the "wrap()" method will cause the subData to be held on, or get garbage collected.

Now, its not easy for me to test this out in my current system since I am actually using this on the Android platform (min API 8). Preferably, I would just "return ByteBuffer.wrap(subData);" and be done with it, but since this function will get calls 100's of thousands of times, I want to be doubly sure its efficent.
  • 1. Re: ByteBuffer's static "wrap" method -- managing memory
    EJP Guru
    Currently Being Moderated
    I have a function which will be called many, many times over:
    Then you already have a problem.
              byte[] subData = new byte[len];
              try {
                   System.arraycopy(data, off, subData, 0, len);
    Here is another one. You are copying data many, many times. Why?
              } catch (Exception e) {
                   e.printStackTrace();
              }
    What exceptions are you expecting here; why are you swallowing them; and why is just printing the stack trace considered adequate handling?
              // TODO find out if null'ing out subData works?
    I don't know what 'works' means, but if you mean 'has any effect' the answer is 'no'. 'The new buffer will be backed by the given byte array', which implies that a reference to the byte array is stored in the `ByteBuffer`, which means that setting other references to null has zero effect.
    This function will get called a LOT...
    All the more reason to remove pointless code from it, but also to investigate whether it needs to be called at all.
    My question this:
    At the end of my code, I null out the "subData" array manually since I am not sure if the "wrap()" method will cause the subData to be held on, or get garbage collected.
    I don't know why you aren't sure. It is clearly implied by the Javadoc. There is no other way that 'modifications to the buffer will cause the array to be modified and vice versa' could be implemented.
    since this function will get calls 100's of thousands of times, I want to be doubly sure its efficent.
    I would be more interested in determining whether it needs to be called at all. Maybe you should be using a ByteBuffer to start with. Maybe you don't really need a ByteBuffer at all. Maybe you don't really need to copy the input array at all: if not, you should just eliminate this method altogether and just call ByteBuffer.wrap() directly in all the call sites concerned.
  • 2. Re: ByteBuffer's static "wrap" method -- managing memory
    1003050 Newbie
    Currently Being Moderated
    Thanks for the reply, let me give you some background information as to why the function will be called many times. I am creating an app on Android that works with Bluetooth and will accept streaming data. The data that is coming in is binary, so I need to cut the data into its chunks and feed it into a float, or short, or int, etc.

    For example, after it comes out the "return ByteBuffer.wrap(..)" I take that output and do a .order(null).getFloat() on it, depending on the byte order.

    As much as I wish I could have used JavaStruct (see GoogleCode) or the C/C++ style Structs to feed in data a-la #pragma(push), I don't see any other way to handle this kind of data. I am hoping that ByteBuffer is very memory efficient and fast.

    Also, as for the "System.arraycopy()" usage, I could look into making that more efficient, however that would require all other methods calling byteArr2ByteBuff to modify how it sends data to this function.

    Thanks for clearing the air on how Null doesn't have any effect though. If you have other ideas on how to handle the parsing of binary packets coming in through a socket, I am definitely all ears!

    PS. I'd rather using Arrays.copyrange instead of the System.arraycopy method, but since I am making this app work for Android API8+, I am limited on the Arrays methods.

    Edited by: 1000047 on Apr 17, 2013 11:42 PM

    For example, here is an example of the usage (sorry not sure how to properly format in sans-serif on this forum yet!)

              public void unpack(byte[] data) {
                   int i = -fSize; //fSize == 4
                   accx = Streams.byteArr2ByteBuff(data, i += fSize, fSize).order(null).getFloat();
                   accy = Streams.byteArr2ByteBuff(data, i += fSize, fSize).order(null).getFloat();
                   accz = Streams.byteArr2ByteBuff(data, i += fSize, fSize).order(null).getFloat();
                   gyrox = Streams.byteArr2ByteBuff(data, i += fSize, fSize).order(null).getFloat();
                   gyroy = Streams.byteArr2ByteBuff(data, i += fSize, fSize).order(null).getFloat();
                   gyroz = Streams.byteArr2ByteBuff(data, i += fSize, fSize).order(null).getFloat();
                   temp = Streams.byteArr2ByteBuff(data, i += fSize, fSize).order(null).getFloat();
              }

    Edited by: 1000047 on Apr 17, 2013 11:45 PM
  • 3. Re: ByteBuffer's static "wrap" method -- managing memory
    EJP Guru
    Currently Being Moderated
    Have a look at DataInputStream, wrapped around a BufferedInputStream, wrapped around your socket. It has all the APIs you need.
  • 4. Re: ByteBuffer's static "wrap" method -- managing memory
    1003050 Newbie
    Currently Being Moderated
    i actually am doing that:
    byte[] buffer = new byte[RawStream.RAWPACKETSIZE]; // this size is 32 right now, by design
                             DataInputStream dis = new DataInputStream(is);
                             dis.readFully(buffer);

    After readfully takes in the buffer, I get the data.

    Now, if I understand correctly, you may be implying to use readFloat() or something like that wtihin DataInputStream. Well, if I will be reciving many, many floats, doesn't that constitute much parsing anyway?

    In other words, say 1024 bytes come in at once and say there will be 200 floats, 50 ints, and the rest shorts, how can DataInputStream correctly know how to parse all that data correctly? In C/C++ one has to build a struct to handle that data. In Java, one must parse the data array...

    Or am I missing something?
  • 5. Re: ByteBuffer's static "wrap" method -- managing memory
    EJP Guru
    Currently Being Moderated
    . Well, if I will be reciving many, many floats, doesn't that constitute much parsing anyway?
    Of course it does. Did you think that using a ByteBuffer was going to magically avoid that?
    In other words, say 1024 bytes come in at once and say there will be 200 floats, 50 ints, and the rest shorts, how can DataInputStream correctly know how to parse all that data correctly?
    It doesn't. You do. You call the methods that are necessary to get whatever comes next in the stream. Just like you're doing now, only without the massive overhead of constantly creating new ByteBuffers.
  • 6. Re: ByteBuffer's static "wrap" method -- managing memory
    1003050 Newbie
    Currently Being Moderated
    Okay, so if I understand right, instead of ever using readFully() to convert the Data input stream (DIS) to a byte array, I should just take the DIS and run:

    .read()
    .readFloat()
    .readInt()
    .readShort()

    etc.

    Those methods will automatically handle the byte order, etc?

    If so, I need to rethink the entire implementation because the methods that are doing the inputstream reading handle both data coming from a network, and data internal to my program that is using PipedIn/outputstream to transfer the streaming data between a reading and writing thread...

    Edited by: esend7881 on Apr 18, 2013 12:55 PM

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points