Node.js Buffer
Node.js Buffer
JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。但在处理像TCP流或文件流时,必须使用到二进制数据。
因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。该缓存区对应 V8 堆内存之外的一块原始内存。
Buffer是典型的JS与C++结合的模块。
在Node启动时就会加载它,并挂载到global全局对象上。
Buffer对象
Buffer对象类似于数组,存放的元素为16进制的两位数(00-FF),即0-255,占用8bit,一个字节。
可通过length获得Buffer的长度(字节数)。
Buffer内存分配
在C++层面申请内存,在JS中分配内存。
slab分配机制
是一种动态内存管理机制。
slab是一块已申请的固定大小的内存区域。有3种状态:
没有分配
部分分配
完全分配。
Node以8KB为界限区分Buffer是大对象还是小对象。
8KB是每个slab的大小,在JS层面,以8KB为单位进行内存分配。
小Buffer对象分配
预先申请slab,事后分配。
一个slab可以存储多个小Buffer对象。
大Buffer对象分配
直接分配一个SlowBuffer对象作为slab单元,Buffer对象独占这个slab,不用详细分配。
SlowBuffer对象是在C++中定义的,使用C++层面的内存。
Buffer的API
创建Buffer
Buffer.alloc()
Buffer.from():数字数组、字符串、Buffer
写入数据
buffer.write()
Buffer与字符编码
通过使用显式的字符编码,就可以在 Buffer 实例与普通的 JavaScript 字符串之间进行相互转换。
1 | const buf = Buffer.from('runoob', 'ascii'); |
支持的字符串编码有限,常见的有:
ASCII
UTF-8
Base64
Hex
Buffer的拼接
流传输时,获取的数据是一段一段的,就是一个Buffer对象。
边传输边按字符串拼接Buffer对象容易导致乱码问题。英文不会乱码,因为是单字节的,中文是多字节的,可能会出现乱码。
正确方法是:将多个小Buffer缓存起来,传输完成后,合并成一个大的Buffer,再转换成字符串。
Buffer与性能
Buffer在文件IO和网络IO中运用广泛。
在应用中我们往往是操作字符串,但在网络传输中,都需要转换成Buffer,传输二进制数据。
在Web应用中,字符转换成Buffer是时时刻刻发生的,提高String转Buffer的效率,可以提高网络吞吐率。
(1)通过预先将静态内容转换成Buffer对象,可以减少CPU重复利用,不用每次响应执行一个Buffer转换。因此,在Web应用中,把动态内容和静态内容分离,静态内容预先转换成Buffer对象。
(2)读取大文件时,highWaterMark越大,读取速度越快。
1 | fs.createReadStream(path, {}); |
highWaterMark对Buffer内存的分配和使用有影响。

