Node笔记七(深入浅出nodejs第一遍阅读读后笔记二)

资源

各种进阶资源 + 联系方式请看下方链接
资源

异步编程
  • 当大量查询本地数据库请求发来时,软件方面可以通过锁,硬件方面可以通过增加服务器来解决
  • EventProxy 是异步协作的一个方法,控制并发 在所有监听事件都完成的前提下执行回调函数
  • bagpipe也是控制异步流程的,用来控制异步并发量
  • Generator与协程
    1. 协程是一种程序运行的方式,可以理解成“协作的线程”或“协作的函数”。协程既可以用单线程实现,也可以用多线程实现。前者是一种特殊的子例程,后者是一种特殊的线程。
    2. 单线程下协程可以调用多个函数并行执行,但是只有一个函数处于运行状态,其余函数处于暂停状态,但可以交换执行权,例如一个函数执行了一半,也可以切换到另一个函数执行 就此循环交替执行.
    3. js是单线程语言,只能保持一个调用栈,引入协程后每个任务可保持自己的调用栈,这样做在抛出错误的时候可以找到原始调用栈.
    4. Generator函数是ES6对协程的不完全实现。Generator被称为“半协程”,意思是只有Generator函数的调用者,才能将程序的执行权还给Genertor函数。若是完全执行的协程,则任何函数都可以让暂停的协程继续执行。
内存控制
  • 内存泄漏:指的是程序中已经动态分布的对内存由于某种原因程序中未释放或无法释放造成系统内存的浪费,导致系统运行速度变慢或者系统崩溃,常见的例子就是:如果页面内存占用过多,基本等不到代码回收用户就已经不耐放的刷新页面了,node内存泄漏主要有缓存,队列消费不及时,作用域未释放这三种。可以使用node-heapdump对内存泄漏进行排查。
  • node中是用的内存是有限制的,这主要受限于V8的内存分配限制,当我们在代码中声明变量并赋值时,所使用的对象的内存就是定义在堆中,如果已申请的堆空间不够分配,新对象就会继续申请,直到超出V8的限制。
  • V8的限制在64位的时候限制1.4GB 32位的时候限制0.7GB,因为js是单线程的机制,所以限制对象的大小是为了回收的时候不影响js线程,如果不限制的话,对象过大会引起主线程卡顿.
  • V8内存空间主要分为新生代和老生代空间,新生代空间主要存储存活时间较短的对象,老生代空间主要存储存活时间较长或常驻内存的对象.
  • 新生代空间通过scavenge算法进行垃圾回收,里面主要采用了Cheney算法,cheney算法是一种采用复制的方式实现的垃圾回收方法,它将堆内存一分为二,分为TO空间和from空间,处于使用状态的空间称为from空间,闲置状态的空间称为TO空间,当我们分配对象时,先是在from空间中进行分配,当垃圾回收时,会检查from空间内的存活对象,这些存活对象会被复制到TO空间中,而非存活对象会被释放内存,完成复制后,from空间和TO空间的角色会被互换,当一个对象被复制多次后依然存活,这个存活的对象会被分配到老生代空间中,对象从新生代移动到老生代过程称之为晋升.
  • 老生代空间中的垃圾回收机制主要通过标记清除法,标记清除分为标记和清除两部分,标记是循环遍历对每一个活着的对象进行标记,在随后的清楚阶段中只清除没有标记的对象
  • 标记清除最大的问题是进行一次清除后,内存空间会出现不连续的状态,类似于链表的数据结构,这时如果再分配过来一个大的对象的时候,碎片空间无法完成此次分配,就会提前触发垃圾回收,而这次回收是没有必要的,因此针对这种情况出现了Mark-Compact,这个是标记整理的意思,标记整理的状态是当标记时,把存活的对象往一端移动,最后清理活着的对象之外的内存,这样就得到了一个连续的内存空间
  • V8的垃圾回收如果全量回收的话会造成很严重的停顿,为了改善这个问题,引入了延时整理和增量回收,就是把大的垃圾回收任务分解为一小段一小段的执行,执行一小段让js代码运行,然后再执行一小段有点类似协程机制
  • 查看垃圾回收日志可以在node启动时添加–trace_gc标志 例如 node --trace_gc -e
  • 通过node启动时添加node --prof 参数可以看到V8执行时的性能分析数据
  • 如何触发垃圾回收
    1. 作用域:在js中可以形成作用域的有函数调用,with,全局作用域.例如 :
    var foo = function () {
       var local = {};
       console.log(bar)
    }; 
    
    在上述代码中foo函数在每次被调用的时候都会创建对应的作用域,函数执行结束后,该作用域会被销毁,同时作用域中分配的局部变量也会因作用域的销毁而销毁,只被局部变量引用的对象存活时间较短,这个对象会被分配在from空间中,在作用域释放后,局部变量local失效,其引用的对象将会在下次垃圾回收时被释放.
  • 作用域链:上述代码中的bar变量在当前作用域内找不到会根据标示符查找一级一级向上查找,就这样形成了作用域链,直到找到全局作用域为止,因为标示符查找只能向上查找所以作用域链只能向外查找。
  • 变量的主动释放:如果变量是全局变量,全局作用域只有当进程结束才会得到释放,此时将导致全局变量引用的对象常驻内存空间,如果需要释放老生代内存空间的对象,可以通过delect操作来删除引用关系,或者重新赋值(可以赋值为undefined或别的),将旧的对象脱离引用关系,在下一次的老生代内存释放中得到释放
  • 闭包:
    var foo = function () {
     var bar = function () {
       var local = "局部变量";
         return function () {
          return local;
            };
           };
      var baz = bar();
      console.log(baz());
    }; 
    
    一般而言,当bar()函数经过调用后里面的变量local会因作用域的销毁而被回收,但是bar()函数的返回值是一个匿名函数,这个匿名函数中具备了访问local变量的条件,虽然在后续的执行中,在外部作用域中还是无法直接访问local,但是要访问这个变量的话,通过baz()这个函数中转下就行了.但是问题在于一旦有外部变量引用这个函数这个函数的内存就得不到释放,除非外部不再引用才会逐级释放。
  • 查看内存使用情况:process.memoryUsage()可以查看V8内存使用情况,os模块中的totalmem()֖查看操作系统的总内存 和 freemem()方法查看操作系统的闲置内存
  • 堆外内存:通过process.momoryUsage()的结果可以看到,堆内的内存用量总是小于进程的常驻内存用量,这意味着node中的内存的使用并非都是通过V8来分配的,我们将那些不是通过V8分配的内存称之为堆外内存.受V8垃圾回收限制的主要是V8的堆内存
  • node大文件操作:node对大文件进行读写时由于V8内存的限制,所以不能使用fs.readFile()֖和fs.writeFile()直接对大文件进行操作,而要通过fs.createReadStream()֖和fs.createWriteStream()方法通过流的方式对大文件进行读写操作,
var reader = fs.createReadStream('in.txt');
var writer = fs.createWriteStream('out.txt');
reader.pipe(writer); 

可读流通过管道方法pipe封装了data()事件和写入操作,通过流的方式,上述代码不会受到V8内存的影响

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值