摘要:且傳入數(shù)據(jù)的大小必須小于。那些固定位數(shù)字讀寫當你在閱讀的文檔時,看到諸如,這樣的時,可能會想到規(guī)范中的類提供的那些方法。
在 Node.js 中,Buffer 常常用來存儲一些潛在的大體積數(shù)據(jù),例如,文件和網(wǎng)絡(luò) I/O 所獲取來的數(shù)據(jù),若不指定編碼,則都以 Buffer 的形式來提供,可見其地位非同一般。你或許聽說過,Buffer 的創(chuàng)建,是可能會經(jīng)過內(nèi)部的一個 8KB 池的,那么具體的規(guī)則是什么呢?可以創(chuàng)建一個新 Buffer 實例的 API 那么多,到底哪些 API 會經(jīng)過,哪些又不會經(jīng)過呢?或許你在閱讀文檔時,還看到過許多形如 Buffer#writeUInt32BE , Buffer#readUInt32BE 等等這類固定位的數(shù)字的讀寫操作,它們具體是如何實現(xiàn)的呢?
現(xiàn)在讓我們一起跟著 Node.js 項目中 lib/buffer.js 中的代碼,來一探究竟。
8KB 池分配規(guī)則統(tǒng)計一下,當前版本的 Node.js (v6.0)中可以創(chuàng)建一個新 Buffer 類實例的 API 有:
new Buffer() (已不推薦使用,可能會泄露內(nèi)存中潛在的敏感信息,具體例子可以看這里)
Buffer.alloc()
Buffer.allocUnsafe()(雖然也有泄露內(nèi)存中敏感信息的可能,但語義上非常明確)
Buffer.from()
Buffer.concat()
跟著代碼追溯,這些 API 最后都會走進兩個內(nèi)部函數(shù)中的一個,來創(chuàng)建 Buffer 實例,這兩個內(nèi)部函數(shù)分別是 createBuffer() 和 allocate():
// lib/buffer.js // ... Buffer.poolSize = 8 * 1024; var poolSize, poolOffset, allocPool; function createPool() { poolSize = Buffer.poolSize; allocPool = createBuffer(poolSize, true); poolOffset = 0; } createPool(); function createBuffer(size, noZeroFill) { flags[kNoZeroFill] = noZeroFill ? 1 : 0; try { const ui8 = new Uint8Array(size); Object.setPrototypeOf(ui8, Buffer.prototype); return ui8; } finally { flags[kNoZeroFill] = 0; } } function allocate(size) { if (size === 0) { return createBuffer(size); } if (size < (Buffer.poolSize >>> 1)) { if (size > (poolSize - poolOffset)) createPool(); var b = allocPool.slice(poolOffset, poolOffset + size); poolOffset += size; alignPool(); return b; } else { return createBuffer(size, true); } }
通過代碼可以清楚的看到,若最后創(chuàng)建時,走的是 createBuffer() 函數(shù),則不經(jīng)過 8KB 池,若走 allocate() 函數(shù),當傳入的數(shù)據(jù)大小小于 Buffer.poolSize 有符號右移 1 位后的結(jié)果(相當于將該值除以 2 再向下取整,在本例中,為 4 KB),才會使用到 8KB 池(若當前池剩余空間不足,則創(chuàng)建一個新的,并將當前池指向新池)。
那么現(xiàn)在讓我們來看看,這些 API 都走的是哪些方法:
// lib/buffer.js // ... Buffer.alloc = function(size, fill, encoding) { // ... return createBuffer(size); }; Buffer.allocUnsafe = function(size) { assertSize(size); return allocate(size); }; Buffer.from = function(value, encodingOrOffset, length) { // ... if (value instanceof ArrayBuffer) return fromArrayBuffer(value, encodingOrOffset, length); if (typeof value === "string") return fromString(value, encodingOrOffset); return fromObject(value); }; function fromArrayBuffer(obj, byteOffset, length) { byteOffset >>>= 0; if (typeof length === "undefined") return binding.createFromArrayBuffer(obj, byteOffset); length >>>= 0; return binding.createFromArrayBuffer(obj, byteOffset, length); } function fromString(string, encoding) { // ... if (length >= (Buffer.poolSize >>> 1)) return binding.createFromString(string, encoding); if (length > (poolSize - poolOffset)) createPool(); var actual = allocPool.write(string, poolOffset, encoding); var b = allocPool.slice(poolOffset, poolOffset + actual); poolOffset += actual; alignPool(); return b; } Buffer.concat = function(list, length) { // ... var buffer = Buffer.allocUnsafe(length); // ... return buffer; };
挺一目了然的,讓我們來總結(jié)一下,當在以下情況同時都成立時,創(chuàng)建的新的 Buffer 類實例才會經(jīng)過內(nèi)部 8KB 池:
通過 Buffer.allocUnsafe,Buffer.concat,Buffer.from(參數(shù)不為一個 ArrayBuffer 實例)和 new Buffer(參數(shù)不為一個 ArrayBuffer 實例)創(chuàng)建。
傳入的數(shù)據(jù)大小不為 0 。
且傳入數(shù)據(jù)的大小必須小于 4KB 。
那些固定位數(shù)字讀寫 API當你在閱讀 Buffer 的文檔時,看到諸如 Buffer#writeUInt32BE,Buffer#readUInt32BE 這樣的 API 時,可能會想到 ES6 規(guī)范中的 DateView 類提供的那些方法。其實它們做的事情十分相似,Node.js 項目中甚至還有將這些 API 的底層都替換成原生的 DateView 實例來操作的 PR ,但該 PR 目前已被標記為 stalled ,具體原因大致是:
沒有顯著的性能提升。
會在實例被初始化后又增加新的屬性。
noAssert 參數(shù)將會失效。
先不管這個 PR ,其實,這些讀寫操作,若數(shù)字的精度在 32 位以下,則對應(yīng)方法都是由 JavaScript 實現(xiàn)的,十分優(yōu)雅,利用了 TypeArray 下那些類(Buffer 中使用的是 Uint8Array)的實例中的元素,在位溢出時,會拋棄溢出位的機制。以 writeUInt32LE 和 writeUInt32BE (LE 和 BE 即小端字節(jié)序和大端字節(jié)序,可以參閱這篇文章)為例,一個 32 位無符號整數(shù)需要 4 字節(jié)存儲,大端字節(jié)序時,則第一個元素為直接將傳入的 32 位整數(shù)無符號右移 24 位,獲取到原最左的 8 位,拋棄當下左邊的所有位。以此類推,第二個元素為無符號右移 16 位,第三個元素為 8 位,第四個元素無需移動(小端字節(jié)序則相反):
Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) { value = +value; offset = offset >>> 0; if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); this[offset] = (value >>> 24); this[offset + 1] = (value >>> 16); this[offset + 2] = (value >>> 8); this[offset + 3] = value; return offset + 4; };
讀操作與之對應(yīng),使用了無符號左移后騰出空位再進行 | 操作合并:
Buffer.prototype.readUInt32BE = function(offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkOffset(offset, 4, this.length); return (this[offset] * 0x1000000) + ((this[offset + 1] << 16) | (this[offset + 2] << 8) | this[offset + 3]); };
其中的 (this[offset] * 0x1000000) + 相當于 this[offset] << 24 | 。
最后參考:
https://github.com/nodejs/node/blob/master/lib/buffer.js
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79349.html
摘要:閑談系列不涉及具體的講解,只會勾勾畫畫一些自己認為比較重要的特性。我們一般認為用兩個字節(jié)位表示,并且完全囊括了字符集。將其轉(zhuǎn)換成進制就是只是表示它們是碼。三的讀取和寫入相關(guān)重要的只有能夠讀寫,才能夠顯示其存在的價值。 原文地址:http://www.cnblogs.com/DeanCh... 在剛接觸Nodejs的時候,有些概念總讓學(xué)前端的我感到困惑(雖然大學(xué)的時候也是在搞后端,世界上...
摘要:在創(chuàng)建時大小已經(jīng)被確定且是無法調(diào)整的,在內(nèi)存分配這塊是由層面提供而不是具體后面會講解。在這里不知道你是否認為這是很簡單的但是上面提到的一些關(guān)鍵詞二進制流緩沖區(qū),這些又都是什么呢下面嘗試做一些簡單的介紹。 showImg(https://segmentfault.com/img/remote/1460000019894717?w=1280&h=850); 多數(shù)人都擁有自己不了解的能力和機...
摘要:端輸入數(shù)據(jù)到端,對就是輸入流,得到的對象就是可讀流對就是輸出端得到的對象是可寫流。在中,這四種流都是的實例,它們都有事件,可讀流具有監(jiān)聽數(shù)據(jù)到來的事件等,可寫流則具有監(jiān)聽數(shù)據(jù)已傳給低層系統(tǒng)的事件等,和都同時實現(xiàn)了和的事件和接口。 原文地址在我的博客 node中的Buffer和Stream會給剛接觸Node的前端工程師們帶來困惑,原因是前端并沒有類似概念(or 有我們也沒意識到)。然而,...
摘要:主要用來檢測對象是否泄漏。子類實現(xiàn)相關(guān)的方法是否支持數(shù)組,判斷緩沖區(qū)的實現(xiàn)是否基于字節(jié)數(shù)組如果緩沖區(qū)的實現(xiàn)基于字節(jié)數(shù)組,返回字節(jié)數(shù)組 ByteBuf ByteBuf需要提供JDK ByteBuffer的功能(包含且不限于),主要有以下幾類基本功能: 7種Java基礎(chǔ)類型、byte[]、ByteBuffer(ByteBuf)的等的讀寫 緩沖區(qū)自身的copy和slice 設(shè)置網(wǎng)絡(luò)字節(jié)序 ...
摘要:回調(diào)函數(shù)提供兩個參數(shù)和,表示有沒有錯誤發(fā)生,是文件內(nèi)容。文件關(guān)閉第一個參數(shù)文件時傳遞的文件描述符第二個參數(shù)回調(diào)函數(shù)回調(diào)函數(shù)有一個參數(shù)錯誤,關(guān)閉文件后執(zhí)行。 showImg(//img.mukewang.com/5d3f890d0001836113660768.jpg); 人所缺乏的不是才干而是志向,不是成功的能力而是勤勞的意志。 —— 部爾衛(wèi) 文章同步到github博客:https:/...
閱讀 3634·2023-04-26 02:32
閱讀 3942·2021-11-23 10:05
閱讀 2302·2021-10-08 10:04
閱讀 2722·2021-09-22 16:06
閱讀 3622·2021-09-22 15:27
閱讀 776·2019-08-30 15:54
閱讀 1722·2019-08-30 13:50
閱讀 2711·2019-08-29 13:56