5

I have a client on Android that uses the TUN interface exposed by the Android VPNService in order to intercept packages. In that regard I read all incoming packets and write them to the TUN interface. This basically means that I do a write for each packet I receive. The problem with this, is that it seems for each write and read call Android allocates int[67] and int[80] respectively, which is a lot of garbage resulting in a lot of recurring garbage collection.

Here is the code for the read operation, which reads all the incoming packets from my server. As mentioned in comments, I read from a simple Datagram Channel:

public void run() {
    ByteBuffer buffer = ByteBuffer.allocate(32767);

    while (!Thread.currentThread().isInterrupted()) {
        try {
            buffer.clear();
            // getVpnTunnel is a simple getter for the underlying datagram channel.
            int packetSize = conn.getVpnTunnel().read(buffer); // int[80] garbage allocated  here
            buffer.flip();

            if (packetSize < 1) {
                // No data, wait then read.
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
                continue;
            }

            switch (...) {
                default:
                    throw new IllegalStateException("Invalid Message Received");
            }
        } catch (IOException e) {
            e.printStackTrace();
            break;
        }
    }
}

When I read a packet/message I strip and check my custom type header (1 byte) and write all the appropriate packets to the Android TUN interface.

Now my question is, is it possible for me to reduce the amount of garbage generated without using buffered reads? Can I cache the exception in any way such that it does not have to allocate a new exception for each read and write call? Or is it simply impossible and should I instead tweak my Thread.sleep waiting time?

Remember, this read call essentially reads all packets received by the client, so I am a bit curious as how much I should sleep. On one hand I do not want to wait while there are packets incoming, but on the other hand, reducing the sleep timer will generate more calls to read, resulting in more frequent garbage collection.

Hope you can give me some advice, thanks in advance.

Simon Langhoff
  • 1,395
  • 3
  • 18
  • 28
  • We are experiencing a similar problem. We can actually reproduce this by having only the `read` command inside the `while` loop, without any additional code. Did you resolve the problem? – noti Nov 17 '15 at 11:55
  • @noti as indicated by the code, it is indeed jus the read method that generates this "garbage". I did however not find a solution and I'm not sure it is possible to avoid having the method generate these bytes. – Simon Langhoff Nov 22 '15 at 10:42
  • 1
    We managed to avoid these bytes by using JNI. Instead of using FileInputStream class, we call the native `read` function, which doesn't throw any exceptions. – noti Nov 22 '15 at 11:30
  • @noti That is actually a very cool solution. At least I do not see any way of preventing this in plain Java. If you were to submit a more written out explanation I would love to have it as an answer to the question. (I'm unsure if using JNI would give any other complications though?). – Simon Langhoff Nov 24 '15 at 15:40

0 Answers0