Sunday, 16 August 2015

Avoid Unnecessary Allocations and Memcpy's

This blog may seem obvious but its worth a mention anyway.

Low latency java needs to follow a different path from standard java and avoid allocations and unnecessary memcpy's.


Consider the following example, how many memory allocations occur for the StringBuilder?

A) Typical java code

private Message read() {
StringBuilder info = new StringBuilder();

Message m = decode();

info.append( "seqNum=" ).append( m.getSeqNum() )
    .append( ", isDup=" ).append( m.isPosDup() )
 
m.dump( info );

log( info );

return m;
}

GC .. who cares ? Multiple allocs per call to read. Threadsafe

B)Presized string buffer

private Message read() {
StringBuilderinfo = new StringBuilder(1024);

Message m = decode();

info.append( "seqNum=" ).append( m.getSeqNum() )
    .append( ", isDup=" ).append( m.isPosDup() )
 
m.dump( info );

log( info );

return m;
}

GC .. who cares ? One buffer alloc per call to read. Threadsafe

C)Member variable

private final StringBuilder _info = new StringBuilder();

private Message read() {

_info.setLength(0);

Message m = decode();

_info.append( "seqNum=" ).append( m.getSeqNum() )
     .append( ", isDup=" ).append( m.isPosDup() )
 
m.dump( _info );

log( _info );

return m;
}

Lazy initialisation for the StringBuilder. Some allocs until buffer hits max required size.
Best option where memory is limited and there can be many instances
Not thread safe ... but thats FINE as all code assumed single threaded unless otherwise specified
In ultra low latency threading model is explicit and all contention minimised and understood.

D)Presized member variable

private final StringBuilder _info = new StringBuilder(1024);

private Message read() {

_info.setLength(0);

Message m = decode();

if ( isLogEnabled() ) {
_info.append( "seqNum=" ).append( m.getSeqNum() )
     .append( ", isDup=" ).append( m.isPosDup() )
 
m.dump( _info );

log( _info );
}

return m;
}

Ok so the guards should of been in all examples, but in typical java code its ignored and the allocations and mempcy paid ... a lazy tax.
Ultra Low Latency approach for the StringBuilder. Single buffer allocation presized to max requirement.
Not thread safe ... but thats FINE as all code assumed single threaded unless otherwise specified
In ultra low latency threading model is explicit and all contention minimised and understood.

FYI SubMicroTrading doesnt use StringBuilder but ReusableString to avoid the overhead of toString() and uses byte instead of char.