BUFFER BENDING


Memory & I/O

WHY NOT USE TYPED ARRAYS

Synonymous with:

Why not kick myself in the groin?

Why not tweeze my facial hair?

Why not program with notepad?

but seriously

Typed Arrays were created around browser security, which introduces unnecessary slow fluff.

How slow?

new Buffer(0xffff);           // 680ns

new Uint8Array(0xffff);       // 8100ns

WHY BUFFERS

Are the medium Streams use to communicate.

JavaScript interface to memory outside the v8 heap.

Best way to work with data in native modules.

With great power comes great responsibility.

DEVELOPER (MIS)USE

WARNING: don't try these without adult supervision

runaway pooling
var arr = [];

for (var i = 0; i < 1e6; i++) {
  arr.push(new Buffer(1));
}



gc();

memory usage: 95 MB

runaway pooling
var arr = [];

for (var i = 0; i < 1e6; i++) {
  arr.push(new Buffer(1));
  // create a buffer for no reason
  new Buffer(Buffer.poolSize);
}

gc();

memory usage: 4370 MB

but why?

            large buffer pool sliced into smaller buffers
---------------------------------------------------------------------
|  A  |      B      |     C     |                 D                 |
---------------------------------------------------------------------
             ∧                                    ∧
             |                                    |
             ∨                                    ∨
---------------------------------------------------------------------
|  A  |             |     C     |                                   |
---------------------------------------------------------------------

After GC only a fraction of memory is used,
but requires the entire pool to hang around.

for indeterminately persistent chunks, don't take a slice

var store = [];

socket.on('readable', function() {
  var data = socket.read();
  // this can cause a memory leak
  store.push(data.slice(0, 10));
});

instead copy out the data

var store = [];

socket.on('readable', function() {
  var data = socket.read();
  // SlowBuffer will now return un-pooled Buffer instance
  var b = new SlowBuffer(10);
  data.copy(b, 0, 0, 10);
  store.push(b);
});
to the heap and back again

Buffer is allocated for data

var buf = new Buffer(1024);      // 290ns

now say we turn it into a string

var str = buf.toString('utf8');  // 315ns - 2670ns

and back to a Buffer on the way out

new Buffer(str);                 // 1075ns - 3350ns

only grab what you need

var b = new Buffer(4096).fill('a');
b[1024] = 10;  // 10 == '\n'

// grab first chunk up to new line
new Buffer(b.toString().split('\n')[0]);  // 3700ns

function find(buf, val) {
  for (var i = 0; i < buf.length; i++)
    if (buf[i] === val)
      return i;
  return -1;
}

length = find(b, 10);                     // 1900ns
sb = new Buffer(length);
b.copy(sb, 0, 0, length);

b.slice(0, find(b, 10));                  // 1600ns
be explicit
var str = 'a';

// str.length == 65536 (same as largest network packet)
for (var i = 0; i < 16; i++)
  str += str;

// default is 'utf8'
Buffer(str);                 // 83200ns
Buffer(str, 'ascii');        // 9700ns

A PEEK AHEAD

WARNING: may change without notice

data on arbitrary objects
var obj = {};
Buffer.alloc(3, obj)
// obj == { 0: 0, 1: 0, 2: 0 }

// no more need for the data
Buffer.dispose(obj);
// obj == {}

but why just Objects

function extDataFn() { }
Buffer.alloc(3, extDataFn);
// { [Function: extDataFn] 0: 0, 1: 0, 2: 0 }

var extRegExp = /^node\.js$/;
Buffer.alloc(3, extRegExp);
// { /^node\.js$/ 0: 0, 1: 0, 2: 0 }

// but this will die
Buffer.alloc(3, []);
manual disposal

Manually free memory attached to a Buffer

var b = new Buffer(5);
// <Buffer 00 00 00 00 00>

b.dispose();
// <Buffer >

prevent GC from doing extra work

function onconnection(handle) {
  handle.server = true;
  handle.onread = function onread(buffer, offset, length) {
    // use data for quick operation
    // e.g. write to disk
    buffer.dispose();
  };
  clientHandle.readStart();
}

before: 15.4Gb/s

after: 20.2Gb/s

INFORMATIONALS

slides:   slid.es/trevnorris/buffer-bending

source:   github.com/trevnorris/talks

tweeter:  twitter.com/trevnorris

freenode: trevnorris (see a pattern here)

Buffer Bending

By trevnorris

Buffer Bending

  • 1,776