@@ -791,11 +791,14 @@ data that might not have been allocated for `Buffer`s.
791791
792792A ` TypeError ` will be thrown if ` size ` is not a number.
793793
794- ### Static method: ` Buffer.allocUnsafe(size) `
794+ ### Static method: ` Buffer.allocUnsafe(size[, alignment] ) `
795795
796796<!-- YAML
797797added: v5.10.0
798798changes:
799+ - version: REPLACEME
800+ pr-url: https://github.com/nodejs/node/pull/65003
801+ description: Added the `alignment` argument.
799802 - version: v20.0.0
800803 pr-url: https://github.com/nodejs/node/pull/45796
801804 description: Throw ERR_INVALID_ARG_TYPE or ERR_OUT_OF_RANGE instead of
@@ -810,6 +813,9 @@ changes:
810813-->
811814
812815* ` size ` {integer} The desired length of the new ` Buffer ` .
816+ * ` alignment ` {integer} If given, the memory backing the new ` Buffer ` will start
817+ at an address that is a multiple of ` alignment ` . Must be a power of two no
818+ larger than ` 2 ** 30 ` . See [ Aligned allocations] [ ] .
813819* Returns: {Buffer}
814820
815821Allocates a new ` Buffer ` of ` size ` bytes. If ` size ` is larger than
@@ -865,11 +871,14 @@ pool, while `Buffer.allocUnsafe(size).fill(fill)` _will_ use the internal
865871difference is subtle but can be important when an application requires the
866872additional performance that [ ` Buffer.allocUnsafe() ` ] [ ] provides.
867873
868- ### Static method: ` Buffer.allocUnsafeSlow(size) `
874+ ### Static method: ` Buffer.allocUnsafeSlow(size[, alignment] ) `
869875
870876<!-- YAML
871877added: v5.12.0
872878changes:
879+ - version: REPLACEME
880+ pr-url: https://github.com/nodejs/node/pull/65003
881+ description: Added the `alignment` argument.
873882 - version: v20.0.0
874883 pr-url: https://github.com/nodejs/node/pull/45796
875884 description: Throw ERR_INVALID_ARG_TYPE or ERR_OUT_OF_RANGE instead of
@@ -881,6 +890,9 @@ changes:
881890-->
882891
883892* ` size ` {integer} The desired length of the new ` Buffer ` .
893+ * ` alignment ` {integer} If given, the memory backing the new ` Buffer ` will start
894+ at an address that is a multiple of ` alignment ` . Must be a power of two no
895+ larger than ` 2 ** 30 ` . See [ Aligned allocations] [ ] .
884896* Returns: {Buffer}
885897
886898Allocates a new ` Buffer ` of ` size ` bytes. If ` size ` is larger than
@@ -5608,16 +5620,92 @@ While there are clear performance advantages to using
56085620[ ` Buffer.allocUnsafe() ` ] [ ] , extra care _ must_ be taken in order to avoid
56095621introducing security vulnerabilities into an application.
56105622
5623+ ### Aligned allocations
5624+
5625+ Some operating system interfaces require the memory they operate on to be
5626+ aligned, and on some hardware alignment is merely faster. The most common
5627+ example of the former is unbuffered ("direct") file I/O, which on Linux requires
5628+ the buffer address, the file offset and the transfer length to all be multiples
5629+ of the logical block size of the underlying device:
5630+
5631+ ``` mjs
5632+ import { open } from ' node:fs/promises' ;
5633+ import { constants } from ' node:fs' ;
5634+ import { Buffer } from ' node:buffer' ;
5635+
5636+ const blockSize = 4096 ;
5637+
5638+ // The buffer address must be block-aligned for O_DIRECT to accept it.
5639+ const buf = Buffer .allocUnsafeSlow (blockSize, blockSize);
5640+
5641+ const file = await open (' /dev/sda' , constants .O_RDONLY | constants .O_DIRECT );
5642+ try {
5643+ await file .read (buf, 0 , blockSize, 0 );
5644+ } finally {
5645+ await file .close ();
5646+ }
5647+ ```
5648+
5649+ ``` cjs
5650+ const fs = require (' node:fs' );
5651+ const { Buffer } = require (' node:buffer' );
5652+
5653+ const blockSize = 4096 ;
5654+
5655+ // The buffer address must be block-aligned for O_DIRECT to accept it.
5656+ const buf = Buffer .allocUnsafeSlow (blockSize, blockSize);
5657+
5658+ const flags = fs .constants .O_RDONLY | fs .constants .O_DIRECT ;
5659+ fs .open (' /dev/sda' , flags, (err , fd ) => {
5660+ if (err) throw err;
5661+ fs .read (fd, buf, 0 , blockSize, 0 , (err ) => {
5662+ fs .close (fd, () => {});
5663+ if (err) throw err;
5664+ });
5665+ });
5666+ ```
5667+
5668+ Alignment can also be worth requesting purely for performance, even when no
5669+ interface demands it. Aligning a hot ` Buffer ` to the cache line size (64 bytes on
5670+ most contemporary CPUs) keeps it from straddling one more cache line than it
5671+ needs to, so that a small structure is fetched with one cache miss instead of
5672+ two, and page-aligned (4096 bytes) allocations similarly help interfaces that map
5673+ or pin memory. These are micro-optimizations: measure before reaching for them,
5674+ since the extra bytes are not free.
5675+
5676+ Because the address of a ` Buffer ` 's memory cannot be chosen directly, extra bytes
5677+ have to be allocated or skipped to reach an aligned address.
5678+ [ ` Buffer.allocUnsafeSlow() ` ] [ ] over-allocates up to ` alignment - 1 ` bytes and
5679+ positions the returned ` Buffer ` at the first suitably aligned byte within them.
5680+ [ ` Buffer.allocUnsafe() ` ] [ ] instead pads its offset into the shared internal pool,
5681+ whose start is always aligned to 64 bytes, and only falls back to an allocation
5682+ of its own when ` alignment ` is larger than that. Either way,
5683+ [ ` buf.byteOffset ` ] [ ] is usually not 0 and [ ` buf.buffer ` ] [ ] is larger than ` size ` ,
5684+ so code that reaches past the ` Buffer ` into its underlying ` ArrayBuffer ` must
5685+ take the offset into account, as it must for pooled ` Buffer ` s.
5686+
5687+ The alignment is a property of the returned ` Buffer ` and is preserved for its
5688+ whole lifetime, but it is not inherited by other views: [ ` buf.subarray ` ] [ ] ,
5689+ [ ` buf.slice() ` ] [ ] and ` structuredClone() ` may all produce unaligned ` Buffer ` s.
5690+
5691+ Alignment also does not survive being captured in a startup snapshot: memory does
5692+ not keep its address across serialization, so a ` Buffer ` allocated while
5693+ [ ` --build-snapshot ` ] [ ] is in effect is not aligned in the deserialized process.
5694+ Allocate inside a [ ` v8.startupSnapshot.setDeserializeMainFunction() ` ] [ ] callback,
5695+ or after startup, if the alignment has to hold at run time.
5696+
56115697[ ASCII ] : https://en.wikipedia.org/wiki/ASCII
5698+ [ Aligned allocations ] : #aligned-allocations
56125699[ Base64 ] : https://en.wikipedia.org/wiki/Base64
56135700[ ISO-8859-1 ] : https://en.wikipedia.org/wiki/ISO-8859-1
56145701[ RFC 4648, Section 5 ] : https://tools.ietf.org/html/rfc4648#section-5
56155702[ UTF-16 ] : https://en.wikipedia.org/wiki/UTF-16
56165703[ UTF-8 ] : https://en.wikipedia.org/wiki/UTF-8
56175704[ WHATWG Encoding Standard ] : https://encoding.spec.whatwg.org/
5705+ [ `--build-snapshot` ] : cli.md#--build-snapshot
56185706[ `Buffer.alloc()` ] : #static-method-bufferallocsize-fill-encoding
5619- [ `Buffer.allocUnsafe()` ] : #static-method-bufferallocunsafesize
5620- [ `Buffer.allocUnsafeSlow()` ] : #static-method-bufferallocunsafeslowsize
5707+ [ `Buffer.allocUnsafe()` ] : #static-method-bufferallocunsafesize-alignment
5708+ [ `Buffer.allocUnsafeSlow()` ] : #static-method-bufferallocunsafeslowsize-alignment
56215709[ `Buffer.concat()` ] : #static-method-bufferconcatlist-totallength
56225710[ `Buffer.copyBytesFrom()` ] : #static-method-buffercopybytesfromview-offset-length
56235711[ `Buffer.from(array)` ] : #static-method-bufferfromarray
@@ -5639,6 +5727,7 @@ introducing security vulnerabilities into an application.
56395727[ `TypedArray.prototype.subarray()` ] : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray
56405728[ `blob.stream()` ] : #blobstream
56415729[ `buf.buffer` ] : #bufbuffer
5730+ [ `buf.byteOffset` ] : #bufbyteoffset
56425731[ `buf.compare()` ] : #bufcomparetarget-targetstart-targetend-sourcestart-sourceend
56435732[ `buf.entries()` ] : #bufentries
56445733[ `buf.fill()` ] : #buffillvalue-offset-end-encoding
@@ -5653,6 +5742,7 @@ introducing security vulnerabilities into an application.
56535742[ `buffer.constants.MAX_STRING_LENGTH` ] : #bufferconstantsmax_string_length
56545743[ `buffer.kMaxLength` ] : #bufferkmaxlength
56555744[ `util.inspect()` ] : util.md#utilinspectobject-options
5745+ [ `v8.startupSnapshot.setDeserializeMainFunction()` ] : v8.md#v8startupsnapshotsetdeserializemainfunctioncallback-data
56565746[ `v8::Uint8Array::kMaxLength` ] : https://v8.github.io/api/head/classv8_1_1Uint8Array.html#a7677e3d0c9c92e4d40bef7212f5980c6
56575747[ base64url ] : https://tools.ietf.org/html/rfc4648#section-5
56585748[ endianness ] : https://en.wikipedia.org/wiki/Endianness
0 commit comments