1.Buffer结构
Buffer是一个像Array的对象,主要用于操作字节
在Node进程启动时就已经加载Buffer,并将其放在全局对象上;无须通过require加载
2.Buffer对象
Buffer对象类似于数组,元素为16进制的两位数,即0~255的数值
length
获取长度 、下标访问元素
3.Buffer内存分配
Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存申请
Node采用slab
分配机制,slab是一种动态内存管理机制,有三种状态:
- full:完全分配
- partial:部分
- empry:没有分配
指定大小的Buffer对象:new Buffer(size)
Node以8K为界限来区分Buffer是大对象还是小对象
- 分配小对象
使用一个局部变量pool作为中间处理对象,处于分配状态的slab单元指向它
var pool
function allocPool(){
pool = new SlowBuffer(Buffer.poolSize)
pool.used=0
}
- 分配大对象
直接分配一个SlowBuffer对象作为slab单元
this.parent = new SlowBuffer(this.length)
this.offset = 0
4.Buffer转换
- 字符串转Buffer
new Buffer(str,encoding)
- Buffer转字符串
buf.toString(encoding,start,end)
- Buffer拼接
Buffer在使用场景中,通常以一段一段的方式传输。
实例:从输入流中读取内容
var fs = require('fs')
var rs = fs.createReadStream('./Node/input.txt')
var data = ''
// chunk对象即是Buffer对象
rs.on('data', function(chunk) {
data += chunk // 隐藏了toString方法
// data = data.toString()+chunk.toString()
})
rs.on('end', function() {
console.log(data)
})
- 中文乱码问题
- 设置编码方式
setEncoding()
在调用setEncoding()时,可读流对象在内部会设置decoder对象;目前只能处理utf8、Base64、UCS-2三种编码 - 正确拼接Buffer:
concat
方法
用数组存储接收到的所有Buffer片段并记录下所有片段的总长度,然后调用Buffer.concat()方法生成一个合并的Buffer对象
5.Buffer与性能
在网络中,通常需要转换为Buffer,以二进制数据传输;提高字符串到Buffer的转化效率,可以提高网络吞吐量
fs.createReadStream()的工作方式是在内存中准备一段Buffer,然后fs.read()读取时逐步从磁盘中将字节复制到Buffer中。完成一次读取,则从这个Buffer中通过slice方法取出部分数据作为一个小Buffer对象,再通过data事件传递给调用方,如果Buffer用完则重新分配一个;如果还有剩余则继续使用