ホームページ  >  記事  >  ウェブフロントエンド  >  Node.js の Buffer モジュールを簡単に理解する

Node.js の Buffer モジュールを簡単に理解する

青灯夜游
青灯夜游転載
2021-11-24 19:20:031596ブラウズ

この記事では、Node.js のバッファを理解し、バッファ構造、バッファ メモリ割り当て、バッファ スプライシングなどについて説明します。皆さんのお役に立てれば幸いです。

Node.js の Buffer モジュールを簡単に理解する

#バッファについて理解する

JavaScript文字列操作に非常に適しています

# Buffer

Array のようなオブジェクトで、主にバイトの操作に使用されます。

バッファ構造

Buffer

は、JavaScript と C を組み合わせた代表的なモジュールです。パフォーマンスに関連する部分は C で実装され、それ以外の部分は C で実装されます。パフォーマンス関連の部分は C で実装されています。一部は JavaScript で実装されています。

Node.js の Buffer モジュールを簡単に理解する#Buffer によって占有されるメモリは V8 を通じて割り当てられず、オフヒープ メモリに属します。 V8 ガベージ コレクションはパフォーマンスに影響を与えるため、より効率的で独自のメモリ割り当てとリサイクル ポリシーを使用して、一般的に使用される操作オブジェクトを管理することをお勧めします。

バッファは、ノード プロセスの開始時にすでに値が設定されており、グローバル オブジェクト (グローバル) に配置されます。

Buffer オブジェクト

Buffer オブジェクトの要素は 2 桁の 16 進数ではなく、つまり、0 ~ 255

let buf01 = Buffer.alloc(8);
console.log(buf01);  // <Buffer 00 00 00 00 00 00 00 00>

の値です。

fill

を使用して buf の値を埋めることができます (デフォルトは utf-8 エンコードです)。値がバッファを超えると、書き込まれません。

バッファ長がコンテンツより大きい場合、バッファは繰り返し埋められます。

以前に埋められたコンテンツをクリアしたい場合は、直接
fill を実行できます。 ()

<pre class="brush:js;toolbar:false;">buf01.fill(&amp;#39;12345678910&amp;#39;) console.log(buf01); // &lt;Buffer 31 32 33 34 35 36 37 38&gt; console.log(buf01.toString()); // 12345678</pre>記入内容が中国語の場合、

utf-8

の影響で、3要素に漢字が入り、文字と半角句読点が入ります。 1要素を占有します。 <pre class="brush:js;toolbar:false;">let buf02 = Buffer.alloc(18, &amp;#39;开始我们的新路程&amp;#39;, &amp;#39;utf-8&amp;#39;); console.log(buf02.toString()); // 开始我们的新</pre>

Buffer

Array type によって大きく影響されます。長さ属性にアクセスして長さを取得したり、添字を使用して要素にアクセスしたりすることもできます。また、indexOf を通じて要素の位置を表示することもできます。 <pre class="brush:js;toolbar:false;">console.log(buf02); // &lt;Buffer e5 bc 80 e5 a7 8b e6 88 91 e4 bb ac e7 9a 84 e6 96 b0&gt; console.log(buf02.length) // 18字节 console.log(buf02[6]) // 230: e6 转换后就是 230 console.log(buf02.indexOf(&amp;#39;我&amp;#39;)) // 6:在第7个字节位置 console.log(buf02.slice(6, 9).toString()) // 我: 取得&lt;Buffer e6 88 91&gt;,转换后就是&amp;#39;我&amp;#39;</pre>バイトに割り当てられた値が 0

255 までの整数ではない場合、または割り当てられた値が 10 進数の場合、割り当てられた値が 0 より小さい場合は、値に 256 を 1 つずつ加算していきます。 0

255 の整数の間の値を取得します。 255 より大きい場合は、255 を 1 つずつ減算します。小数の場合は、小数部分を切り捨てます (四捨五入なし)

バッファ メモリ割り当て

バッファ

オブジェクトのメモリ割り当ては、 V8 ヒープ内 メモリ内では、メモリ アプリケーションはノードの C レベルで実装されます。大量のバイト データを処理する場合、メモリが必要なときにオペレーティング システムからメモリを申請できないためです。このため、Node は C レベルのメモリを使用して JavaScript

Node

スラブ割り当てメカニズムを採用します, slab は動的メモリ管理メカニズムであり、現在 Linuxslab などの一部の

*nix

オペレーティング システムで広く使用されています。スラブには次の 3 つの状態があります:

full: 完全に割り当てられた状態
  • partial: 部分的な割り当てステータス
  • empty: 割り当てられていないステータス
  • ノードは、バッファがラージ オブジェクトかスモール オブジェクトかを区別するための制限として
8KB

を使用します。

console.log(Buffer.poolSize);  // 8192

この 8KB の値は各スラブのサイズです。JavaScript レベルでは、メモリ割り当ての単位として使用されます

#小さなバッファ オブジェクトを割り当てます

指定された Buffer

サイズが 8KB 未満の場合、ノードはスモール オブジェクト メソッド

に従ってサイズを割り当てます。新しいスラブ ユニットを構築します。スラブは現在空の状態です。

Node.js の Buffer モジュールを簡単に理解する 1024KB の小さな

buffer
    オブジェクトを構築します。現在の
  1. slab は 1024KB で占有されます。レコードはどこからのものです この slab はどこから使用され始めますか?

Node.js の Buffer モジュールを簡単に理解するこの時点で、

を作成しますサイズが 3072KB のbuffer
    オブジェクト。構築プロセスでは、現在の
  1. slab の残りのスペースが十分であるかどうかが判断され、十分な場合は、残りのスペースを使用して、slab の割り当てステータスを更新します。 3072KB のスペースが使用された後、このスラブの残りのスペースは現在 4096KB です。

Node.js の Buffer モジュールを簡単に理解するこの時点で 6144KB のサイズの

buffer
    を作成すると、現在のスラブ領域では不十分であり、新しいスラブ領域が
  1. スラブが構築されます (これにより、元のスラブの残りのスペースが無駄になります)

たとえば、次のようになります。例: ###

Buffer.alloc(1)
Buffer.alloc(8192)

第一个slab中只会存在1字节的buffer对象,而后一个buffer对象会构建一个新的slab存放

由于一个slab可能分配给多个Buffer对象使用,只有这些小buffer对象在作用域释放并都可以回收时,slab的空间才会被回收。 尽管只创建1字节的buffer对象,但是如果不释放,实际是8KB的内存都没有释放

小结:

真正的内存是在Node的C++层面提供,JavaScript层面只是使用。当进行小而频繁的Buffer操作时,采用slab的机制进行预先申请和时候分配,使得JavaScript到操作系统之间不必有过多的内存申请方面的系统调用。 对于大块的buffer,直接使用C++层面提供的内存即可,无需细腻的分配操作。

Buffer的拼接

buffer在使用场景中,通常是以一段段的方式进行传输。

const fs = require(&#39;fs&#39;);

let rs = fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;});
let str = &#39;&#39;
rs.on(&#39;data&#39;, (chunk)=>{
    str += chunk;
})

rs.on(&#39;end&#39;, ()=>{
    console.log(str);
})

以上是读取流的范例,data时间中获取到的chunk对象就是buffer对象。

但是当输入流中有宽字节编码(一个字占多个字节)时,问题就会暴露。在str += chunk中隐藏了toString()操作。等价于str = str.toString() + chunk.toString()

下面将可读流的每次读取buffer长度限制为11.

fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;, highWaterMark: 11});

输出得到:

Node.js の Buffer モジュールを簡単に理解する

上面出现了乱码,上面限制了buffer长度为11,对于任意长度的buffer而言,宽字节字符串都有可能存在被截断的情况,只不过buffer越长出现概率越低。

encoding

但是如果设置了encodingutf-8,就不会出现此问题了。

fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;, highWaterMark: 11, encoding:&#39;utf-8&#39;});

Node.js の Buffer モジュールを簡単に理解する

原因: 虽然无论怎么设置编码,流的触发次数都是一样,但是在调用setEncoding时,可读流对象在内部设置了一个decoder对象。每次data事件都会通过decoder对象进行buffer到字符串的解码,然后传递给调用者。

string_decoder 模块提供了用于将 Buffer 对象解码为字符串(以保留编码的多字节 UTF-8 和 UTF-16 字符的方式)的 API

const { StringDecoder } = require(&#39;string_decoder&#39;);
let s1 = Buffer.from([0xe7, 0xaa, 0x97, 0xe5, 0x89, 0x8d, 0xe6, 0x98, 0x8e, 0xe6, 0x9c])
let s2 = Buffer.from([0x88, 0xe5, 0x85, 0x89, 0xef, 0xbc, 0x8c, 0x0d, 0x0a, 0xe7, 0x96])
console.log(s1.toString());
console.log(s2.toString());
console.log(&#39;------------------&#39;);

const decoder = new StringDecoder(&#39;utf8&#39;);
console.log(decoder.write(s1));
console.log(decoder.write(s2));

Node.js の Buffer モジュールを簡単に理解する

StringDecoder在得到编码之后,知道了宽字节字符串在utf-8编码下是以3个字节的方式存储的,所以第一次decoder.write只会输出前9个字节转码的字符,后两个字节会被保留在StringDecoder内部。

Buffer与性能

buffer在文件I/O和网络I/O中运用广泛,尤其在网络传输中,性能举足轻重。在应用中,通常会操作字符串,但是一旦在网络中传输,都需要转换成buffer,以进行二进制数据传输。 在web应用中,字符串转换到buffer是时时刻刻发生的,提高字符串到buffer的转换效率,可以很大程度地提高网络吞吐率。

如果通过纯字符串的方式向客户端发送,性能会比发送buffer对象更差,因为buffer对象无须在每次响应时进行转换。通过预先转换静态内容为buffer对象,可以有效地减少CPU重复使用,节省服务器资源。

可以选择将页面中动态和静态内容分离,静态内容部分预先转换为buffer的方式,使得性能得到提升。

在文件的读取时,highWaterMark设置对性能影响至关重要。在理想状态下,每次读取的长度就是用户指定的highWaterMark

highWaterMark大小对性能有两个影响的点:

  • 对buffer内存的分配和使用有一定影响
  • 设置过小,可能导致系统调用次数过多

更多node相关知识,请访问:nodejs 教程!!

以上がNode.js の Buffer モジュールを簡単に理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。