Buffer.Buffer — это Node.js-специфичная вещь, в браузере его нет. Технически он наследуется от Uint8Array, то есть это тот же TypedArray, но с дополнительными методами для удобной работы со строками и файлами:
const b = Buffer.from('hello', 'utf8');
b.toString('hex'); // '68656c6c6f'
У
Buffer есть три статических метода для аллокации, и они работают принципиально по-разному.Buffer.alloc(size) — безопасный вариант. Создаёт отдельный ArrayBuffer нужного размера, память заполняется нулями. Пул не используется.
Buffer.alloc(8); // <Buffer 00 00 00 00 00 00 00 00>
Buffer.allocUnsafe(size) — быстрый вариант. Память не обнуляется, в буфере могут быть остатки старых данных. Но самое интересное — это то, как он выделяет память.Buffer.allocUnsafeSlow(size) — как allocUnsafe, но всегда создаёт отдельный ArrayBuffer, без пула. Зачем — объясню ниже.Когда вы вызываете
Buffer.allocUnsafe(100), Node.js не идёт каждый раз просить систему выделить 100 байт. Вместо этого он заранее выделяет один большой кусок памяти на 8 КБ (пул) и нарезает от него маленькие буферы:Если запрошенный размер меньше 4096 байт (половина от размера всего пула), Node.js просто двигает указатель внутри пула и создаёт новый view на уже существующий
ArrayBuffer. Новой аллокации памяти нет, поэтому это очень быстро.Если в текущем пуле не хватает места — создаётся новый. Если запрошенный буфер слишком большой (≥ 4096) — пул не используется, создаётся отдельный
ArrayBuffer.Порог в половину пула выбран не случайно: если буфер занимает больше половины, он съест почти весь пул, а оставшийся хвост станет бесполезным.
После каждой нарезки
poolOffset выравнивается до границы в 8 байт. Это нужно для производительности: невыровненный доступ к памяти на некоторых архитектурах медленнее.Все маленькие буферы, нарезанные из одного пула, разделяют один
ArrayBuffer. Это значит: пока хотя бы один такой буфер жив, все 8 КБ пула не могут быть собраны GC.Именно для этого существует
Buffer.allocUnsafeSlow(size) — он всегда создаёт отдельный ArrayBuffer. Если вы создаёте много маленьких буферов и удерживаете их надолго (кешируете, складываете в массив), allocUnsafeSlow может быть экономичнее по памяти.