水落石穿
1: Buffer 为什么不用 require来引入;
Buffer 是node的全局对象;
深入一下Buffer 的性能是由c++ 实现,非性能是有javaScript实现的;
Buffer 的内存不是由V8引擎分配的,他在V8所在内存的外面;启动node的时候,会把Buffer 挂载在全局对象上(global);
2: Buffer 的前世今生:
Buffer 继承 UintArray 继承 TypedArray
let buff = new Buffer(8);
buff instanceof Buffer //true
buff instanceof Uint8Array //true
buff instanceof TypedArray //Error TypedArray is not defined
//TypedArray 并没有在全局对象中, Uint8Array 的原型函数指向它所创建的实例
console.log(typeof Uint8Array.prototype) //"object"
console.log(buff instanceof Uint8Array.prototype.constructor) //true
3: Buffer 元素的最大值:
let buff = new Buffer(1);
buff[0] 所占的内存为1个字节8位,最大值为255
buff[0] = 256;
console.log(buff[0]) //0 至于为什么等于0 属于2进制的内容了;
4: Buffer 的对象的储存位置:
let buff = new Buffer(1); //buff 所指向的地址 并不在V8的内存中,而是在V8之外的内存中, Node 的 C++ 层面实现内存的申请;
申请内存后,分配权在js的手里;
5: node 的slab内存分配策略;
slab有三个状态:
full:完全分配状态
partial:部分分配状态
empty:未被分配状态
在创建buffer对象的时候,会根据大小是否超过8kb,在node的c++层次申请不同的内存;分为大对象,小对象;
超过8kb 使用大对象,不超过使用小对象
在分配小对象内存过程中后又一个中间局部变量来参与资源的分配:pool;
let pool;
Buffer.poolSize = 1024*8;//长度8kb
function allocPool() {
pool = new SlowBuffer(Buffer.poolSize);
pool.used = 0;
};
//此时,slab 处于 empty 状态。
let buf = new Buffer(12);//length=12;
// 如果当前poll为undefined 或者 poll 剩下的内存不足以储存buf对象,就会创建一个新的poll对象
if(!pool || pool.length- pool.used < buf.length){
allocPool();
}
//同时当前 Buffer 对象的 parent 属性指向该 slab,并记录下是从这个 slab 的哪个位置(offset)开始使用的,slab 对象自身也记录被使用了多少字节:
this.parent = pool;
this.offset = pool.used;
pool.used += this.length;
if (pool.used & 7) pool.used = (pool.used + 8) & ~7;
此时的sold 的状态为partial;
当长度大于8kb的时候,我们就会申请一个大对象
let pool;
function allocPool(length) {
pool = new SlowBuffer(length);
pool.used = length;
};
//当Buffer对象的长度大于1024*8的时候,该对象单独占用一个内存块;
let buff = new BUff(1024*9)
if(buff.length > 1024*8){
buff.parent = new SlowBuffer(this.length);
buff.offset = 0;
}
6: 关于内存的销毁:
这里主要说的是小内存的销毁,小内存里面保存着至少1个Buffder对象,当该内存中所有的内存没有被引用的时候,释放该内存;
也就是会,释放内存是整体释放,只要其中一个内存被引用,那么其他不再被引用的内存还是存在的;当那个唯一被引用的内存不再引用的时候,整体释放整个小内存块;