>  기사  >  웹 프론트엔드  >  Node.js의 Buffer 모듈을 간략하게 이해하세요.

Node.js의 Buffer 모듈을 간략하게 이해하세요.

青灯夜游
青灯夜游앞으로
2021-11-24 19:20:031579검색

이 기사에서는 Node.js의 버퍼를 이해하고 버퍼 구조, 버퍼 메모리 할당, 버퍼 스플라이싱 등에 대해 살펴보겠습니다. 도움이 되길 바랍니다!

Node.js의 Buffer 모듈을 간략하게 이해하세요.

버퍼 이해

JavaScript는 문자열 연산에 매우 친숙합니다.JavaScript对于字符串的操作十分友好

Buffer是一个像Array的对象,主要用于操作字节。

Buffer结构

Buffer是一个典型的JavaScript和C++结合的模块,将性能相关部分用C++实现,将非性能相关部分用JavaScript实现。

Node.js의 Buffer 모듈을 간략하게 이해하세요.

Buffer所占用的内存不是通过V8分配,属于堆外内存。 由于V8垃圾回收性能影响,将常用的操作对象用更高效和专有的内存分配回收政策来管理是个不错的思路。

Buffer在Node进程启动时就已经价值,并且放在全局对象(global)上。所以使用buffer无需require引入

Buffer对象

Buffer对象的元素未16进制的两位数,即0-255的数值

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

可以使用fill填充buf的值(默认为utf-8编码),如果填充的值超过buffer,将不会被写入。

如果buffer长度大于内容,则会反复填充

如果想要清空之前填充的内容,可以直接fill()

buf01.fill(&#39;12345678910&#39;)

console.log(buf01);   // <Buffer 31 32 33 34 35 36 37 38>
console.log(buf01.toString()); // 12345678

如果填入的内容是中文,在utf-8的影响下,中文字会占用3个元素,字母和半角标点符号占用1个元素。

let buf02 = Buffer.alloc(18, &#39;开始我们的新路程&#39;, &#39;utf-8&#39;);
console.log(buf02.toString());  // 开始我们的新

BufferArray类型影响很大,可以访问length属性得到长度,也可以通过下标访问元素,也可以通过indexOf查看元素位置。

console.log(buf02);  // <Buffer e5 bc 80 e5 a7 8b e6 88 91 e4 bb ac e7 9a 84 e6 96 b0>
console.log(buf02.length)  // 18字节
console.log(buf02[6])  // 230: e6 转换后就是 230
console.log(buf02.indexOf(&#39;我&#39;))  // 6:在第7个字节位置
console.log(buf02.slice(6, 9).toString())  // 我: 取得<Buffer e6 88 91>,转换后就是&#39;我&#39;

如果给字节赋值不是0255之间的整数,或者赋值时小数时,赋值小于0,将该值逐次加256.直到得到0255之间的整数。如果大于255,就逐次减去255。 如果是小数,舍去小数部分(不做四舍五入)

Buffer内存分配

Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存的申请。 因为处理大量的字节数据不能采用需要一点内存就向操作系统申请一点内存的方式。为此Node在内存上使用的是在C++层面申请内存,在JavaScript中分配内存的方式

Node采用了slab分配机制slab是以中动态内存管理机制,目前在一些*nix操作系统用中有广泛的应用,比如Linux

slab就是一块申请好的固定大小的内存区域,slab具有以下三种状态:

  • full:完全分配状态
  • partial:部分分配状态
  • empty:没有被分配状态

Node以8KB为界限来区分Buffer是大对象还是小对象

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

这个8KB的值就额是每个slab的大小值,在JavaScript层面,以它作为单位单元进行内存的分配

分配小buffer对象

如果指定Buffer大小小于8KB,Node会按照小对象方式进行分配

  1. 构造一个新的slab单元,目前slab处于empty空状态

Node.js의 Buffer 모듈을 간략하게 이해하세요.

  1. 构造小buffer对象1024KB,当前的slab会被占用1024KB,并且记录下是从这个slab的哪个位置开始使用的

Node.js의 Buffer 모듈을 간략하게 이해하세요.

  1. 这时再创建一个buffer对象,大小为3072KB。 构造过程会判断当前slab剩余空间是否足够,如果足够,使用剩余空间,并更新slab的分配状态。 3072KB空间被使用后,目前此slab剩余空间4096KB。

Node.js의 Buffer 모듈을 간략하게 이해하세요.

  1. 如果此时创建一个6144KB大小的buffer,当前slab空间不足,会构造新的slab
  2. BufferArray와 같은 객체이며 주로 사용됩니다. 바이트를 조작합니다.

버퍼 구조Node.js의 Buffer 모듈을 간략하게 이해하세요.

버퍼는 JavaScript와 C++를 결합한 대표적인 모듈입니다. 성능 관련 부분은 C++로 구현됩니다. 성능과 관련되지 않은 부분은 JavaScript로 구현됩니다.

Node.js의 Buffer 모듈을 간략하게 이해하세요.🎜🎜버퍼 점유된 메모리는 V8을 통해 할당되지 않으며 오프힙 메모리에 속합니다. V8 가비지 수집이 성능에 미치는 영향으로 인해 일반적으로 사용되는 작업 개체를 보다 효율적이고 독점적인 메모리 할당 및 재활용 정책으로 관리하는 것이 좋습니다. 🎜
🎜Buffer는 Node 프로세스가 시작될 때 이미 값이 지정되어 전역 개체(global)에 배치됩니다. 따라서 버퍼를 사용할 때 🎜

🎜Buffer object🎜

🎜를 도입할 필요가 없습니다. Buffer 개체의 요소는 16진수 두 자리가 아닙니다. 숫자, 즉 0-255 숫자 값 ​​🎜
Buffer.alloc(1)
Buffer.alloc(8192)
🎜은 fill을 사용하여 buf 값을 채울 수 있습니다(기본값은 utf-8 인코딩입니다). 채워진 값이 버퍼를 초과하면 기록되지 않습니다. 🎜
🎜버퍼 길이가 내용보다 크면 반복적으로 채워집니다🎜
🎜이전에 채워진 내용을 지우고 싶다면 직접 fill()을 하면 됩니다🎜
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);
})
🎜채워진 내용이 중국어라면 utf-8의 영향으로 한자는 3요소, 글자와 반각 구두점은 1요소를 차지하게 됩니다. 🎜
fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;, highWaterMark: 11});
🎜버퍼배열 유형의 영향을 크게 받습니다. 길이 속성에 액세스하여 길이를 얻을 수도 있고, 아래 첨자를 통해 요소에 액세스할 수도 있습니다. 또한 indexOf를 통해 요소 위치를 봅니다. 🎜
fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;, highWaterMark: 11, encoding:&#39;utf-8&#39;});
🎜바이트에 할당된 값이 0255 사이의 정수가 아니거나 할당된 값이 소수인 경우 할당된 값이 0보다 작은 경우 다음을 추가하세요. 256을 0에서 255 사이의 정수를 얻을 때까지 하나씩 값으로 변환합니다. 255보다 크면 255를 하나씩 뺍니다. 소수이면 소수 부분을 버립니다(반올림 없음)🎜

🎜버퍼 메모리 할당🎜

🎜버퍼의 메모리 할당 V8의 힙 메모리에서는 메모리 적용이 Node.js의 C++ 레벨에서 구현됩니다. 왜냐하면 대용량 바이트 데이터를 처리할 때 메모리가 필요할 때 운영체제에서 메모리를 일부 신청할 수 없기 때문이다. 이러한 이유로 Node는 C++ 수준에서 메모리 애플리케이션을 사용하고 JavaScript🎜🎜에서 메모리를 할당합니다. Node슬랩 할당 메커니즘, 를 채택합니다. slab은 동적 메모리 관리 메커니즘으로, 현재 Linux🎜🎜와 같은 일부 *nix 운영 체제에서 널리 사용됩니다. slab은 적용된 고정 크기 메모리 영역 🎜
  • full: 완전히 할당된 상태 🎜
  • partial: 부분적으로 할당된 상태 🎜
  • Empty: 할당되지 않은 상태 🎜
🎜Node는 Buffer가 큰 개체인지 작은 개체인지 구분하기 위해 🎜8KB🎜를 제한으로 사용합니다.🎜
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));
🎜8KB 값은 JavaScript 수준에서 각 슬랩의 크기를 사용합니다. 메모리 할당 단위로🎜

🎜작은 버퍼 개체 할당🎜

🎜Buffer를 지정하는 경우 크기가 8KB 미만이면 Node에서 Small Object 방식에 따라 할당합니다🎜
  1. 현재 슬래브는 빈 상태입니다🎜🎜🎜Node.js의 Buffer 모듈을 간략하게 이해하세요.🎜
    1. 작은 버퍼 code> 객체 1024KB, 현재 slab는 1024KB를 차지하며 이 slab가 사용되는 위치를 기록합니다🎜🎜🎜Node.js의 Buffer 모듈을 간략하게 이해하세요.🎜
      1. 이때 3072KB 크기의 또 다른 buffer 객체를 생성합니다. 시공 과정에서 현재 슬래브의 남은 공간이 충분한지 판단합니다. 충분하다면 남은 공간을 활용하고 슬래브의 할당 상태를 업데이트합니다. 3072KB 공간을 사용한 후 이 슬래브의 남은 공간은 현재 4096KB입니다. 🎜🎜🎜Node.js의 Buffer 모듈을 간략하게 이해하세요.🎜
      2. 이때 6144KB 버퍼가 생성되면 현재 슬래브 공간이 부족하여 새로운 슬래브가 구축됩니다(이 남은 공간이 낭비됩니다) 🎜🎜🎜🎜🎜🎜예를 들어 다음 예에서는 🎜
        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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제