memory leak?

edited October 2013 in Questions about Code

Could someone check if the following test code crashes on their computer?

The code is a stripped down skeleton of a data acquisiton program, but it still produces the same OutOfMemoryError after 109 s. Increasing the max. available memory to 1024 kB, its "lifetime" also increases to about 440 s.

(Processing 2.0.3, Win7, 2GB)

Test code:

import processing.net.*;

int port = 10002;
Server myServer;
Client myClient;

int bigByteArraySize = 1000000;  // 10^6
byte[] bigByteBuffer = new byte[bigByteArraySize];
byte[] smallByteBuffer = new byte[bigByteArraySize/10];
int startTime;


void setup() {
  myServer = new Server(this, port);
  myClient = new Client(this, "127.0.0.1", port);
  thread("serverWrite");
  startTime = millis();
}

void draw() {
  if ( myClient.available() > bigByteArraySize ) {

    // Read the bytes
    myClient.readBytes(bigByteBuffer);
    println("elapsed time = " + (millis()-startTime)/1000.0 + " s");

    // Print memory usage
    printMem();

    // Garbage collector - won't help :(
    System.gc();
  }
}


// Simulate server (data rate < 1 MB/s)
void serverWrite() {
  while (true) {
    myServer.write(smallByteBuffer);
    delay(100);
  }
}

// Print memory usage
void printMem() {
  int maxMemMB = int(Runtime.getRuntime().maxMemory()/1024/1024);
  int totalMemMB = int(Runtime.getRuntime().totalMemory()/1024/1024);
  int freeMemMB = int(Runtime.getRuntime().freeMemory()/1024/1024);
  println("memory [MB]:" + " max: " + maxMemMB + " | total: " + totalMemMB + " | free: " + freeMemMB);
}
Tagged:

Comments

  • 1024 kB should have been 1024 MB, sorry.

  • Whoever (benfry?) wrote the Client class in the Network library, had warned of the memory leak I described above.

    This is an excerpt from Client.java:

              synchronized (buffer) {
                // todo: at some point buffer should stop increasing in size, 
                // otherwise it could use up all the memory.
                if (bufferLast == buffer.length) {
                  byte temp[] = new byte[bufferLast << 1];
                  System.arraycopy(buffer, 0, temp, 0, bufferLast);
                  buffer = temp;
                }
                buffer[bufferLast++] = (byte)value;
              }
    

    Client starts with a buffer of a decent size:

      byte buffer[] = new byte[32768];
    

    But whenever it gets full (bufferLast == buffer.length), its size will be doubled. That would be harmless, if after some time bufferLast, the "write index" could not reach the length of the buffer.

    bufferLast, the "write index" is rewound when bufferIndex, the "read index" catches up with it or the clear() method clears the buffer. Unfortunately, readBytes(bytebuffer), the method I used in my faulty code will never rewind bufferLast if called after this condition:

    if ( myClient.available() > bigByteArraySize ) 
    

    That I think explains the memory leak. What is still not clear to me is why - according to the reference - readBytes(bytebuffer) is "more memory and time efficient" than a simple readBytes().

Sign In or Register to comment.