目录
Buffer的出现解决了什么问题
- 解决了JavaScript在处理二进制流方面的软肋。例如流和文件操作,因为与操作系统或其它进程的交互总是以二进制数据的形式发生。
- 可以突破Node内存限制,可以更大范围使用内存。
区别
# 声明
let str = 'xxx'; // String可以直接使用字面量声明
let buf1 = Buffer.from('xxx') // Buffer 需要通过Buffer.from来创建
# 拼接
let str3 = `str1:${ str1 }str2:${ str2 }`;
let buf3 = Buffer.concat([buf1, buf2], buf1.length + buf2.length);
# 性能
由于buffer是二进制数据,而string是字符串数据,在网络传输过程中是以二进制流进行传输的,所以buffer的传输效率较string会略胜一筹。
# 注意,buffer也会产生乱码,在使用createReadStream读取字节流的时候,由于data太大,所以导致分为多次传输,中间存在截断的现象。为了在拼接的过程中不产生乱码,提供以下两种方法
- 将所有的数据读取以后,然后再拼接buffer,最后使用三方库iconv-lite转码
- 再获取到buffer数据的时候,使用bufferData.setEncoding('utf8');// 其实内部是使用了string_decoder
这两种方法有一个区别,第一种方法是获取所有的buffer后再拼接,然后转码,而第二种方法是获取多少转多少。
内存管理
Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存的申请中。因为处理大量的字节数据不能采用需要一点内存就向OS申请一点内存的方式,这可能造成大量内存申请的系统调用,对OS有一定压力。
在Node里面,默认将Buffer分为两种对象:数据大于8 * 1024字节的大对象和小于 8 * 1024 的小对象。
# 创建两个大对象变量,两次申请内存
let buf1 = Buffer.alloc(8200);
let buf1 = Buffer.alloc(8200);
# 创建两个小对象,一次内存申请
let buf2 = Buffer.alloc(10);
let buf3 = Buffer.alloc(100);
同样是两次变量申请,前者两次系统调用,后者一次系统调用。原因是内部有一个控制内存申请的阈值,默认是 8 * 1024,可以通过Buffer.poolSize进行调整。