Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebSocket frequent onmessage zero-copy

I have an app that receives binary messages over a WebSocket frequently (at least once per frame) and plots the data, using canvas/webgl. I've noticed that I have a pretty good saw-tooth memory profile; lots of short lived chunks of data. enter image description here

This does not surprise me since I'm receiving an object from onmessage, at least once every 16ms, which is used for drawing and then de-referenced.

My question is: are there any tips for avoiding/minimizing this? Based on the WebSocket API, there doesn't seem to be an alternative to having new memory allocated on every socket receive call. In another language/environment, I'd pre-allocate some memory and receive into that buffer, to avoid constantly allocating memory for short lived objects, but I can't think of any obvious way to achieve this in JavaScript in the browser.

For reference, here is my Frames view.

enter image description here

I don't know if that idle time is garbage collection? Any dev-tools ninja insights would be greatly appreciated.

like image 531
sethro Avatar asked Nov 03 '15 22:11

sethro


1 Answers

Not sure if I understood your problem but you can declare a global array like in any other language and use it as a circular buffer, for example:

var buffer = [];
var bufferLength = 1000;
var start = 0;
var end = 0;
var content = 0;

socket.onmessage(function(msg) { //msg allocated
    end %= bufferLength;
    if (end == start && content != 0)
        console.log("Buffer is full");
    else {
        content++;
        buffer[end++] = msg; //reference to msg saved so it's not destroyed at the end of the callback
    }
});

function getNext() {
    start %= bufferLength;
    if (start == end && content == 0)
        console.log("Buffer is empty");
    else {
        content--;
        return buffer[start++]; // returns reference to next msg
    }
}

Edit: I modified the answer to be more clear about the memory cycle:

JS will allocate memory for the received message on websockets and will create a reference to it called msg that will be given to you as a param in the callback defined for onmessage.

Note JS GC will only destroy that memory piece when it is not referenced anymore in the code.

What I do above is saving that reference inside a buffer so the value does not get destroyed when the callback is done and you can access it later using getNext. You don't need to allocate new memory because JS did it for you.

In case you want to clone or create a different copy of msg, there are some different options. A simple option that will allow you to clone a non-circular JSON object would be:

var newJSON = JSON.parse(JSON.stringify(msg));

You can find more information about memory allocation in JS in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management

like image 161
Javier Conde Avatar answered Nov 11 '22 07:11

Javier Conde