1. A Buffer
è solo una vista per guardare in un ArrayBuffer
.
A Buffer
, infatti, è una FastBuffer
, che extends
(eredita da) Uint8Array
, che è un ottetto unità view ( “di accesso parziale”) della memoria effettiva, un ArrayBuffer
.
📜 Node.js 9.4.0/lib/buffer.js#L65-L73
class FastBuffer extends Uint8Array {
constructor(arg1, arg2, arg3) {
super(arg1, arg2, arg3);
}
}
FastBuffer.prototype.constructor = Buffer;
internalBuffer.FastBuffer = FastBuffer;
Buffer.prototype = FastBuffer.prototype;
2. La dimensione di an ArrayBuffer
e la dimensione della sua vista possono variare.
Motivo # 1: Buffer.from(arrayBuffer[, byteOffset[, length]])
.
Con Buffer.from(arrayBuffer[, byteOffset[, length]])
, è possibile creare un Buffer
con specificando il suo sottostante ArrayBuffer
e la posizione e le dimensioni della vista.
const test_buffer = Buffer.from(new ArrayBuffer(50), 40, 10);
console.info(test_buffer.buffer.byteLength); // 50; the size of the memory.
console.info(test_buffer.length); // 10; the size of the view.
Motivo n. 2: FastBuffer
allocazione della memoria.
Alloca la memoria in due modi diversi a seconda delle dimensioni.
- Se la dimensione è inferiore alla metà della dimensione di un pool di memoria e non è 0 ("piccola") : utilizza un pool di memoria per preparare la memoria richiesta.
- Altrimenti : crea un apposito
ArrayBuffer
che si adatta perfettamente alla memoria richiesta.
📜 Node.js 9.4.0/lib/buffer.js#L306-L320
function allocate(size) {
if (size <= 0) {
return new FastBuffer();
}
if (size < (Buffer.poolSize >>> 1)) {
if (size > (poolSize - poolOffset))
createPool();
var b = new FastBuffer(allocPool, poolOffset, size);
poolOffset += size;
alignPool();
return b;
} else {
return createUnsafeBuffer(size);
}
}
📜 Node.js 9.4.0/lib/buffer.js#L98-L100
function createUnsafeBuffer(size) {
return new FastBuffer(createUnsafeArrayBuffer(size));
}
Cosa intendi con " pool di memoria "?
Un pool di memoria è un blocco di memoria pre-allocato di dimensioni fisse per mantenere blocchi di memoria di piccole dimensioni per Buffer
s. Usandolo si mantengono strettamente i blocchi di memoria di piccole dimensioni, quindi si evita la frammentazione causata dalla gestione separata (allocazione e deallocazione) di blocchi di memoria di piccole dimensioni.
In questo caso, i pool di memoria sono di ArrayBuffer
dimensioni predefinite di 8 KiB, che è specificato in Buffer.poolSize
. Quando deve fornire un blocco di memoria di piccole dimensioni per a Buffer
, controlla se l'ultimo pool di memoria dispone di memoria sufficiente per gestirlo; in tal caso, crea un oggetto Buffer
che "visualizza" il blocco parziale dato del pool di memoria, altrimenti crea un nuovo pool di memoria e così via.
È possibile accedere al sottostante ArrayBuffer
di a Buffer
. Il Buffer
's buffer
di proprietà (che è, ereditato da Uint8Array
) lo tiene. Un “piccolo” Buffer
's buffer
proprietà è un ArrayBuffer
che rappresenta l'intero pool di memoria. Quindi, in questo caso, la ArrayBuffer
e Buffer
varia in dimensioni.
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
// A `Buffer`'s `length` property holds the size, in octets, of the view.
// An `ArrayBuffer`'s `byteLength` property holds the size, in octets, of its data.
console.info(zero_sized_buffer.length); /// 0; the view's size.
console.info(zero_sized_buffer.buffer.byteLength); /// 0; the memory..'s size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
console.info(small_buffer.length); /// 3; the view's size.
console.info(small_buffer.buffer.byteLength); /// 8192; the memory pool's size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
console.info(big_buffer.length); /// 4096; the view's size.
console.info(big_buffer.buffer.byteLength); /// 4096; the memory's size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
3. Quindi abbiamo bisogno di estrarre la memoria che " vede ".
Un ArrayBuffer
è di dimensioni fisse, quindi è necessario estrarlo facendo una copia della parte. Per fare questo, usiamo Buffer
la byteOffset
proprietà e la length
proprietà , che sono ereditate da Uint8Array
, e il ArrayBuffer.prototype.slice
metodo , che fa una copia di una parte di un ArrayBuffer
. Il slice()
metodo -ing qui è stato ispirato da @ZachB .
const test_buffer = Buffer.from(new ArrayBuffer(10));
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
function extract_arraybuffer(buf)
{
// You may use the `byteLength` property instead of the `length` one.
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
}
// A copy -
const test_arraybuffer = extract_arraybuffer(test_buffer); // of the memory.
const zero_sized_arraybuffer = extract_arraybuffer(zero_sized_buffer); // of the... void.
const small_arraybuffer = extract_arraybuffer(small_buffer); // of the part of the memory.
const big_arraybuffer = extract_arraybuffer(big_buffer); // of the memory.
console.info(test_arraybuffer.byteLength); // 10
console.info(zero_sized_arraybuffer.byteLength); // 0
console.info(small_arraybuffer.byteLength); // 3
console.info(big_arraybuffer.byteLength); // 4096
4. Miglioramento delle prestazioni
Se si desidera utilizzare i risultati in sola lettura o è corretto modificare il Buffer
contenuto dell'input , è possibile evitare la copia di memoria non necessaria.
const test_buffer = Buffer.from(new ArrayBuffer(10));
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
function obtain_arraybuffer(buf)
{
if(buf.length === buf.buffer.byteLength)
{
return buf.buffer;
} // else:
// You may use the `byteLength` property instead of the `length` one.
return buf.subarray(0, buf.length);
}
// Its underlying `ArrayBuffer`.
const test_arraybuffer = obtain_arraybuffer(test_buffer);
// Just a zero-sized `ArrayBuffer`.
const zero_sized_arraybuffer = obtain_arraybuffer(zero_sized_buffer);
// A copy of the part of the memory.
const small_arraybuffer = obtain_arraybuffer(small_buffer);
// Its underlying `ArrayBuffer`.
const big_arraybuffer = obtain_arraybuffer(big_buffer);
console.info(test_arraybuffer.byteLength); // 10
console.info(zero_sized_arraybuffer.byteLength); // 0
console.info(small_arraybuffer.byteLength); // 3
console.info(big_arraybuffer.byteLength); // 4096