BUFFER BENDING
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?
Typed Arrays were created around browser security, which introduces unnecessary slow fluff.
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
var arr = [];
for (var i = 0; i < 1e6; i++) {
arr.push(new Buffer(1));
}
gc();
memory usage: 95 MB
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);
});
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
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
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, []);
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
How slow?