小程序二进制图片 buffer存储_Node.js之Buffer对象浅析

前端开发的盲点,Node开发的基础

29d524ab88409b5d381b27d1250a030f.gif

01 前言

前端的开发人员一般是不会去关注Buffer的对象的,在大多数人看来前端就是写页面的程序员,但现在随着Node的发展,越来越多的前端工程师关注一些后端的开发流程。撇开前端的业务开发,我们来了解一下Node的工作都和哪些知识点打交道。

与应用型的场景不一样,Node中需要处理网络协议、操作数据库、处理图片、接受上传文件等。我们知道在网络当中,数据都是以二进制的形式传播,现有的JavaScript已经不能满足要求了,所以Buffer应运而生。

02 Buffer

Buffer是一个像Array的对象,它的元素都是16进制的两位数。是一个典型的JavaScript与C++结合的模块,设计性能的相关部分采用了C++实现,而非性能部分采用了JavaScript实现。Buffer对象可以用来操作二进制数据流

由于Buffer经常用于字符串以及大文件等操作,我们知道Node有垃圾收集机制,大对象不太可能存放在堆中,不然内存很快就会满了。buffer所占用的内存其实不是堆中的,而是堆外内存。Node在加载的时候就已经加载这个对象,并把它放在了全局对象上面。

71483d51b644e31cd7f15e1153394c78.png

03 内存管理模型

Node程序在运行过程中,此进程占据的所有内存成为常驻内存。它由以下几个部分组成:

  • 代码区
  • 堆外内存

他们之间的关系如下图:

317e42ee91fa7a1fd224e5a610b2634c.png

04 Buffer内存分配

我们知道,Buffer对象的内存分配不是在V8的堆内存中的,而是由Node的C++层面实现的内存申请的。由于大对象的存储空间是不确定的,不可能向操作系统申请,会对操作系统造成压力。所以Node在内存的使用上面应用的是C++层面申请内存,在JavaScript中分配内存的策略。

那么它的具体分配策略是怎么样的呢?大对象和小对象的分配方式采用的算法是否是一样的呢?

首先来介绍一下 slab 内存分配机制。它是一种动态内存管理机制,采用的是预先申请,事后分配的方式,简单来说它就是一块申请好的固定大小的内存区域。有如下3种状态:

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

这种机制是以 8KB为界限来决定当前分配的对象是大对象还是小对象,也就是每一个slab的值。在JavaScript层面以它作为单位单元进行内存的分配。

①小对象内存分配

我们在这里引入一个pool局部对象,Buffer在小对象的分配过程中会使用pool作为中间处理对象。

85581621bdeda226b670c6573f3e1cee.png

上图这个是刚申请的slab内存块的状态是 empty 状态,等待被分配,而下图是被两个小对象分配后的状态,为partial状态。值得注意的是,在一个小对象分配之前会判断这个 pool 空间是否还够,如果不够的话就会重新申请一块新的8KB内存来分配。

所以一块 slab 可以被多个对象占有,加入第一次分配了1KB,但是下一个内存则要8KB,那么就造成了内存的浪费。这个1KB的小对象就占据了一整块内存。而且内存的释放规则是所有的对象释放之后,这块8KB的slab才会回收。

V8 GC 对其不直接起作用,Buffer 对象被 GC 的时候会触发一个回调(C++ 层面的回调),而 Node.js 源码中定义的那个回调里面做的事就是释放那块内存。

e28e5e76df1a683e36be4f46bdb8be38.png

②大对象内存分配

如果这个对象是超过了 slab 的大小,那么就不会占用slab块,直接使用C++层面分配你所需要的大小,这块空间就会被你一直占有。举个简单的例子就是:

就像银行办理普通业务的客人一样,都规矩地在前台办理,但是VIP客户可以直接找银行行长。这里每一位银行业务员都是一个个slab,都是预先分配好的,然后VIP客人的需求可能更大,那么就直接找行长办理,无需繁杂的手续。

684f2679e45cd2b9e9cbe97bf00a0ae8.png

这里我们总结一下,Buffer对象都是在JavaScript层面的,能够被V8的垃圾回收机制标记回收的。但是Buffer操作的字节真正的内存是在Node的C++层面提供的,JavaScript层面只是使用它。不论是小 Buffer 对象还是大 Buffer 对象,内存分配是在 C++ 层面完成,内存管理在 JavaScript 层面。如果解除两者的引用,Buffer对象最终还是可以被 V8 的垃圾回收标记所回收。

c39791f4be0b67151307bf241ad34915.png

05 小结

Buffer对象是Node服务端的一个重要的概念,占据着很重要的位置。不论我们读写文件还是网络请求都会用到这个对象,可能前端的开发人员不会过多关注这个东西。

通过对buffer对象的内存分配,我们在以后的编程当中应该时刻关注着变量的分配,因为如果内存一旦泄露,1G的服务器内存也会很快地被占用完,严重的话会造成服务器的崩溃。

参考文章

  • 深入浅出Node.js
  • 探究不在V8堆内存中存储得Buffer对象

欢迎大家关注我的个人公众号《前端小时》

d150c22327bf108b317b066c18cf175b.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值