深刻淺出Node.js學習筆記(六)

理解Buffer

1. Buffer結構

Buffer是一個像Array的對象,但它主要用於操做字節。node

1.1 模塊結構

Buffer是一個典型的JavaScript與C++結合的模塊,它將性能相關的部分用C++實現,將非性能相關的部分用JavaScript實現。數組

Buffer所佔用的內存不是經過V8分配的,屬於堆外內存。bash

因爲Buffer太過常見,Node在進程啓動時就已經加裝了它,並將其放在全局對象(global)上。服務器

1.2 Buffer對象

Buffer對象相似於數組,它的元素爲16進制的兩位數,即0到255的數值。函數

var str = "深刻淺出node.js";
var buf = new Buffer(str, 'utf-8');
console.log(buf);
// => <Buffer e6 b7 b1 e5 85 a5 e6 b5 85 e5 87 ba 6e 6f 64 65 2e 6a 73>
複製代碼

1.3 Buffer內存分配

Buffer對象的內存分配不是在V8的堆內存中,而是在Node的C++層面實現內存的申請的。由於 處理大量的字節數據不能採用須要一點內存就想操做系統申請一旦內存的方式,這可能形成大量的內存申請的系統調用,對操做系統有必定的壓力。爲此Node在內存的使用上應用的是在C++層面申請內存、在JavaScript中分配內存的策略。性能

爲了高效地使用申請來的內存,Node採用了slab分配機制。編碼

slab是一種動態內存管理機制。spa

slab是一塊申請好的固定大小的內存區域。操作系統

slab的3中狀態:code

  1. full:徹底分配狀態;
  2. partial:部分分配狀態;
  3. empty:沒有被分配狀態;

new一個指定大小的Buffer對象:

new Buffer(size)
複製代碼

Node以8KB爲界限來區分Buffer是大對象仍是小對象。

8KB的值也就是每一個slab的大小值,在JavaScript層面,以它做爲單位單元進行內存分配。

  1. 分配小Buffer對象

    若是指定Buffer的大小少於8KB,Node會按照小對象的方式進行分配。Buffer的分配過程當中主要使用一個局部變量做爲中間處理對象,處於分配狀態的slab單元都指向它。

  2. 分配大buffer對象

    若是須要超過8KB的Buffer對象,將會直接分配一個SlowBuffer對象做爲slab做爲slab單元,這個slab單元將會被這個大Buffer對象獨佔。

  3. 小結

    真正的內存是在Node的C++層面提供的,JavaScript層數只是使用它。當進行小而頻繁的Buffer操做時,採用slab的機制進行預先申請和過後分配,使得JavaScript到操做系統之間沒必要有過多的內存申請方面的系統調用。對於大Buffer而言,則直接使用C++層面提供的內存,而無需細膩的分配操做。

2. Buffer的轉換

Buffer對象能夠也字符串之間相互轉換。支持的字符串編碼有:

  1. ASCII
  2. UTF-8
  3. UTF-16LE/UCS-2
  4. Base64
  5. Binary
  6. Hex

2.1 字符串轉Buffer

字符串轉Buffer對象主要經過構造函數完成的:

new Buffer(str,[encoding]);
複製代碼

2.2 Buffer轉字符串

Buffer對象的toString()能夠將Buffer對象轉換爲字符串。

buf.toString([encoding],[start],[end]);
複製代碼

2.3 Buffer不支持的編碼類型

Buffer提供了一個isEncoding()函數來判斷編碼是否支持轉換。

Buffer.isEncoding(encodinh)
複製代碼

3. Buffer的拼接

Buffer在使用場景中,一般是以一段一段的方式傳輸。

3.1 亂碼是如何產生的

對於任意長度的Buffer而言,寬字節字符串都有可能存在被截取的狀況,這是致使亂碼產生的緣由。

3.2 setEncoding()與string_decoder()

setEncoding():設置編碼的方法,讓data事件中傳遞的再也不是一個Buffer對象,而是編碼後的字符串。

string_decoder模塊是StringDecoder的實例對象。

3.3 正確拼接Buffer

正確的拼接方式是用一個數組存儲接收到的全部Buffer片斷的總長度,而後調用Buffer.concat()方法生成一個合併的Buffer對象。Buffer。concat()方法封裝了從小Buffer對象向大Buffer對象的複製過程。

4. Buffer與性能

經過預先轉換靜態內容爲Buffer對象,能夠有效地減小CPU的重複使用,節省服務器資源。在Node構建的Web應用中,能夠選擇將頁面的動態內容和靜態內容分離,靜態內容部分能夠經過預先轉換爲Buffer的方式,使得性能獲得提高。

  • 文件讀取

    Buffer的使用在文件讀取時,有一個highWaterMark設置對性能的影響相當重要。

    讀取一個相同的大文件時,highWaterMark值的大小與讀取速度的關係:該值越大,讀取速度越快。

相關文章
相關標籤/搜索