Node.js의 Buffer 모듈을 간략하게 이해하세요.
이 기사에서는 Node.js의 버퍼를 이해하고 버퍼 구조, 버퍼 메모리 할당, 버퍼 스플라이싱 등에 대해 살펴보겠습니다. 도움이 되길 바랍니다!
버퍼 이해
JavaScript
는 문자열 연산에 매우 친숙합니다.JavaScript
对于字符串的操作十分友好
Buffer
是一个像Array
的对象,主要用于操作字节。
Buffer结构
Buffer
是一个典型的JavaScript和C++结合的模块,将性能相关部分用C++实现,将非性能相关部分用JavaScript实现。
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('12345678910') 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, '开始我们的新路程', 'utf-8'); console.log(buf02.toString()); // 开始我们的新
Buffer
受Array类型
影响很大,可以访问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('我')) // 6:在第7个字节位置 console.log(buf02.slice(6, 9).toString()) // 我: 取得<Buffer e6 88 91>,转换后就是'我'
如果给字节赋值不是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会按照小对象方式进行分配
- 构造一个新的slab单元,目前slab处于empty空状态
- 构造小
buffer
对象1024KB,当前的slab
会被占用1024KB,并且记录下是从这个slab
的哪个位置开始使用的
- 这时再创建一个
buffer
对象,大小为3072KB。 构造过程会判断当前slab
剩余空间是否足够,如果足够,使用剩余空间,并更新slab
的分配状态。 3072KB空间被使用后,目前此slab剩余空间4096KB。
- 如果此时创建一个6144KB大小的
buffer
,当前slab空间不足,会构造新的slab
Buffer
는 Array
와 같은 객체이며 주로 사용됩니다. 바이트를 조작합니다. 버퍼 구조
버퍼
는 JavaScript와 C++를 결합한 대표적인 모듈입니다. 성능 관련 부분은 C++로 구현됩니다. 성능과 관련되지 않은 부분은 JavaScript로 구현됩니다. 
🎜Buffer는 Node 프로세스가 시작될 때 이미 값이 지정되어 전역 개체(global)에 배치됩니다. 따라서 버퍼를 사용할 때 🎜
🎜Buffer object🎜
🎜를 도입할 필요가 없습니다. Buffer 개체의 요소는 16진수 두 자리가 아닙니다. 숫자, 즉 0-255 숫자 값 🎜Buffer.alloc(1) Buffer.alloc(8192)
fill
을 사용하여 buf 값을 채울 수 있습니다(기본값은 utf-8
인코딩입니다). 채워진 값이 버퍼를 초과하면 기록되지 않습니다. 🎜🎜버퍼 길이가 내용보다 크면 반복적으로 채워집니다🎜🎜이전에 채워진 내용을 지우고 싶다면 직접
fill()
을 하면 됩니다🎜 const fs = require('fs'); let rs = fs.createReadStream('./静夜思.txt', { flags:'r'}); let str = '' rs.on('data', (chunk)=>{ str += chunk; }) rs.on('end', ()=>{ console.log(str); })
utf-8
의 영향으로 한자는 3요소, 글자와 반각 구두점은 1요소를 차지하게 됩니다. 🎜fs.createReadStream('./静夜思.txt', { flags:'r', highWaterMark: 11});
버퍼
는 배열 유형
의 영향을 크게 받습니다. 길이 속성에 액세스하여 길이를 얻을 수도 있고, 아래 첨자를 통해 요소에 액세스할 수도 있습니다. 또한 indexOf를 통해 요소 위치를 봅니다. 🎜fs.createReadStream('./静夜思.txt', { flags:'r', highWaterMark: 11, encoding:'utf-8'});
🎜버퍼 메모리 할당🎜
🎜버퍼
의 메모리 할당 V8의 힙 메모리에서는 메모리 적용이 Node.js의 C++ 레벨에서 구현됩니다. 왜냐하면 대용량 바이트 데이터를 처리할 때 메모리가 필요할 때 운영체제에서 메모리를 일부 신청할 수 없기 때문이다. 이러한 이유로 Node는 C++ 수준에서 메모리 애플리케이션을 사용하고 JavaScript
🎜🎜에서 메모리를 할당합니다. Node
는 슬랩 할당 메커니즘
, 를 채택합니다. slab
은 동적 메모리 관리 메커니즘으로, 현재 Linux
🎜🎜와 같은 일부 *nix
운영 체제에서 널리 사용됩니다. slab
은 적용된 고정 크기 메모리 영역 🎜- full: 완전히 할당된 상태 🎜
- partial: 부분적으로 할당된 상태 🎜
- Empty: 할당되지 않은 상태 🎜
const { StringDecoder } = require('string_decoder'); 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('------------------'); const decoder = new StringDecoder('utf8'); console.log(decoder.write(s1)); console.log(decoder.write(s2));
🎜8KB 값은 JavaScript 수준에서 각 슬랩의 크기를 사용합니다. 메모리 할당 단위로🎜
🎜작은 버퍼 개체 할당🎜
🎜Buffer
를 지정하는 경우 크기가 8KB 미만이면 Node에서 Small Object 방식에 따라 할당합니다🎜- 현재 슬래브는 빈 상태입니다🎜🎜🎜
🎜
- 작은 < 구성 code>버퍼 code> 객체 1024KB, 현재
slab
는 1024KB를 차지하며 이slab
가 사용되는 위치를 기록합니다🎜🎜🎜🎜
- 이때 3072KB 크기의 또 다른
buffer
객체를 생성합니다. 시공 과정에서 현재슬래브
의 남은 공간이 충분한지 판단합니다. 충분하다면 남은 공간을 활용하고슬래브
의 할당 상태를 업데이트합니다. 3072KB 공간을 사용한 후 이 슬래브의 남은 공간은 현재 4096KB입니다. 🎜🎜🎜🎜< ol start="4">
- 이때 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('fs'); let rs = fs.createReadStream('./静夜思.txt', { flags:'r'}); let str = '' rs.on('data', (chunk)=>{ str += chunk; }) rs.on('end', ()=>{ console.log(str); })
로그인 후 복사로그인 후 복사以上是读取流的范例,data时间中获取到的chunk对象就是buffer对象。
但是当输入流中有宽字节编码(
一个字占多个字节
)时,问题就会暴露。在str += chunk
中隐藏了toString()
操作。等价于str = str.toString() + chunk.toString()
。下面将可读流的每次读取buffer长度限制为11.
fs.createReadStream('./静夜思.txt', { flags:'r', highWaterMark: 11});
로그인 후 복사로그인 후 복사输出得到:
上面出现了乱码,上面限制了buffer长度为11,对于任意长度的buffer而言,宽字节字符串都有可能存在被截断的情况,只不过buffer越长出现概率越低。
encoding
但是如果设置了
encoding
为utf-8
,就不会出现此问题了。fs.createReadStream('./静夜思.txt', { flags:'r', highWaterMark: 11, encoding:'utf-8'});
로그인 후 복사로그인 후 복사原因: 虽然无论怎么设置编码,流的触发次数都是一样,但是在调用
setEncoding
时,可读流对象在内部设置了一个decoder对象
。每次data事件都会通过decoder对象
进行buffer到字符串的解码,然后传递给调用者。string_decoder
模块提供了用于将 Buffer 对象解码为字符串(以保留编码的多字节 UTF-8 和 UTF-16 字符的方式)的 APIconst { StringDecoder } = require('string_decoder'); 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('------------------'); const decoder = new StringDecoder('utf8'); console.log(decoder.write(s1)); console.log(decoder.write(s2));
로그인 후 복사로그인 후 복사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 중국어 웹사이트의 기타 관련 기사를 참조하세요!
- 이때 3072KB 크기의 또 다른
- 작은 < 구성 code>버퍼 code> 객체 1024KB, 현재

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제









Non-Blocking, Event-Driven 기반으로 구축된 Node 서비스는 메모리 소모가 적다는 장점이 있으며, 대규모 네트워크 요청을 처리하는데 매우 적합합니다. 대규모 요청을 전제로 '메모리 제어'와 관련된 문제를 고려해야 합니다. 1. V8의 가비지 수집 메커니즘과 메모리 제한 Js는 가비지 수집 기계에 의해 제어됩니다.

이 기사는 NodeJS V8 엔진의 메모리 및 가비지 수집기(GC)에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다.

파일 모듈은 파일 읽기/쓰기/열기/닫기/삭제 추가 등과 같은 기본 파일 작업을 캡슐화한 것입니다. 파일 모듈의 가장 큰 특징은 모든 메소드가 **동기** 및 ** 두 가지 버전을 제공한다는 것입니다. 비동기**, sync 접미사가 있는 메서드는 모두 동기화 메서드이고, 없는 메서드는 모두 이기종 메서드입니다.

Node 19가 정식 출시되었습니다. 이 글에서는 Node.js 19의 6가지 주요 기능에 대해 자세히 설명하겠습니다. 도움이 되셨으면 좋겠습니다!

Node용 Docker 이미지를 선택하는 것은 사소한 문제처럼 보일 수 있지만 이미지의 크기와 잠재적인 취약점은 CI/CD 프로세스와 보안에 상당한 영향을 미칠 수 있습니다. 그렇다면 최고의 Node.js Docker 이미지를 어떻게 선택합니까?

Node.js는 GC(가비지 수집)를 어떻게 수행하나요? 다음 기사에서는 이에 대해 설명합니다.

노드가 npm 명령을 사용할 수 없는 이유는 환경 변수가 올바르게 구성되지 않았기 때문입니다. 해결 방법은 다음과 같습니다. 1. "시스템 속성"을 엽니다. 2. "환경 변수" -> "시스템 변수"를 찾은 다음 환경을 편집합니다. 3. nodejs 폴더의 위치를 찾습니다. 4. "확인"을 클릭합니다.

이벤트 루프는 Node.js의 기본 부분이며 메인 스레드가 차단되지 않도록 하여 비동기 프로그래밍을 가능하게 합니다. 이벤트 루프를 이해하는 것은 효율적인 애플리케이션을 구축하는 데 중요합니다. 다음 기사는 Node.js의 이벤트 루프에 대한 심층적인 이해를 제공할 것입니다. 도움이 되기를 바랍니다!
