如何计算 Node.js GC 负载

2023-11-15

在 Node.js 中,我们关注的比较的是 CPU 负载,但是在有 GC 的语言中,GC 负载也是需要关注的一个指标,因为 GC 过高会影响我们应用的性能。本文介绍关于 GC 负载的一些内容。

如何获取 GC 耗时

操作系统本身会计算每隔线程的 CPU 耗时,所以我们可以通过系统获取这个数据,然后计算出线程的 CPU 负载。但是 GC 不一样,因为 GC 是应用层的一个概念,操作系统是不会感知的,在 Node.js 里,具体来说,是在 V8 里,也没有 API 可以直接获取 GC 的耗时,但是 V8 提供了一些 GC 的钩子函数,我们可以借助这些钩子函数来计算出 GC 的负载。其原理和 CPU 负载类似。V8 提供了以下两个钩子函数,分别在 GC 开始和结束时会执行。

Isolate::GetCurrent()->AddGCPrologueCallback();
Isolate::GetCurrent()->AddGCEpilogueCallback();

通过这两个函数,我们就可以得到每一次 GC 的耗时,再不断累积就可以计算出 GC 的总耗时,从而计算出 GC 负载。下面看一下核心实现。

static void BeforeGCCallback(Isolate* isolate,
                             v8::GCType gc_type,
                             v8::GCCallbackFlags flags,
                             void* data) {
    GCLoad* gc_load = static_cast<GCLoad*>(data);
    if (gc_load->current_gc_type != 0) {
        return;
    }
    gc_load->current_gc_type = gc_type;
    gc_load->start_time = uv_hrtime();
}

static void AfterGCCallback(Isolate* isolate,
                            v8::GCType gc_type,
                            v8::GCCallbackFlags flags,
                            void* data) {
    GCLoad* gc_load = static_cast<GCLoad*>(data);
    if (gc_load->current_gc_type != gc_type) {
        return;
    }
    gc_load->current_gc_type = 0;
    gc_load->total_time += uv_hrtime() - gc_load->start_time;
    gc_load->start_time = 0;
}

void GCLoad::Start(const FunctionCallbackInfo<Value>& args) {
    GCLoad* obj = ObjectWrap::Unwrap<GCLoad>(args.Holder());
    Isolate::GetCurrent()->AddGCPrologueCallback(BeforeGCCallback, static_cast<void*>(obj));
    Isolate::GetCurrent()->AddGCEpilogueCallback(AfterGCCallback, static_cast<void*>(obj));
}

可以看到思路很简单,就是注册两个 GC 钩子函数,然后在 GC 开始钩子中记录开始时间,然后在 GC 结束钩子中记录结束时间,并算出一次 GC 的耗时,再累加起来,这样就可以得到任意时刻 GC 的总耗时,但是拿到总耗时如何计算出 GC 负载呢?

如何计算 GC 负载

负载 = 过去一段时间内的消耗 / 过去的一段时间值,看看如何计算 GC 负载。

class GCLoad {
    lastTime;
    lastTotal;
    binding = null;
    start() {
        if (!this.binding) {
            this.binding = new binding.GCLoad();
            this.binding.start();
        }
    }
    stop() {
        if (this.binding) {
            this.binding.stop();
            this.binding = null;
        }
    }
    load() {
        if (this.binding) {
            const { lastTime, lastTotal } = this;
            const now = process.hrtime();
            const total = this.binding.total();
            this.lastTime = now;
            this.lastTotal = total;
            if (lastTime && lastTotal) {
                const cost = total - lastTotal;
                const interval = (now[0] - lastTime[0]) * 1e6 + (now[1] - lastTime[1]) / 1e3;
                return cost / interval;
            }
        }
    }
    total() {
        if (this.binding) {
            return this.binding.total();
        }
    }
}

计算算法也很简单,就是记录上次的时间和 GC 耗时,然后下次需要记录某个时刻的 GC 负载时,就拿当前的耗时减去上次的耗时,并拿当前的时间减去上次的时间,然后得到过去一段时间内的耗时和过去的时间大小,一处就得到 GC 负载了。

使用

下面看看如何使用。

const { GCLoad } = require('..');
const gcLoad = new GCLoad();
gcLoad.start();
setInterval(() => {
    for (let i = 0; i < 1000; i++) {
        new Array(100);
    }
    gc();
    console.log(gcLoad.load());
}, 3000);

执行上面代码会(node --expose-gc demo.js) 在我电脑上输出如下。

0.004235378248715853
0.004100483670865412
0.0017808558192331187
0.002371772559838465
0.0024768595957239477

这样就可以得到了应用的 GC 负载。

完整代码参考 https://github.com/theanarkh/nodejs-native-gc-load。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何计算 Node.js GC 负载 的相关文章

随机推荐

  • java并发包:重入锁与Condition条件

    本文转载至 http blog csdn net a910626 article details 51900941 重入锁 这里介绍一下synchronized wait notify方法的替代品 或者说是增强版 重入锁 重入锁是可以完全替
  • redis--13--Jedis使用

    redis 13 Jedis使用 代码位置 https gitee com DanShenGuiZu learnDemo tree master redis learn jedis 1 redis conf 修改 允许远程连接 bind 1
  • Java异常-Exception

    一 异常介绍 基本概念 Java语言中 将程序执行中发生的不正常情况称为 异常 注 开发过程中的语法错误和逻辑错误不是异常 执行过程中所发生的异常事件可分为两大类 Error 错误 Java虚拟机无法解决的严重问题 如 JVM系统内部错误
  • 2023-05-18 题目

    2023 05 18 题目 1 String 字符串 String 不是基本数据类型 且是不能被继承的 因为string类被final修饰 源码 public final class String implements java io Se
  • [FreeRTOS入门学习笔记]定时器

    定时器的使用步骤 1 定义一个handle xTimerCreate创建 2 启动定时器 在Task1中调用 通过队列通知守护任务来执行定时器任务 要再config头文件中定义守护任务相关配置 虽然定时器是在task1中启动 但是定时器的任
  • qt实现opengl播放yuv视频

    qt使用opengl播放yuv视频 文章目录 qt使用opengl播放yuv视频 toc 1 实现效果 2 pro文件 3 xvideowidget h 4 xvideowidget cpp 更多精彩内容 个人内容分类汇总 1 实现效果 2
  • VS2022编译GDAL库报错: fatal error U1050: PROJ_INCLUDE should be defined. PROJ >= 6 is a required depende

    目录 场景复现 定位问题 解决方案 踩过的坑 场景复现 使用VS2022的Native Tools command prompt for 2022工具编译GDAL库时 报 fatal error U1050 PROJ INCLUDE sho
  • RTSP视频边缘计算网关EasyNVR在5G时代有什么运用价值?

    5G和互联网的发展在近几年一直被按下了加速键 物联网正在成为主流 毋庸置疑 云计算为越来越多智能设备的连接提供了基础 给我们生活带来了极大便利 而边缘计算是云计算物联当中的一个关键应用 当我们在考虑云计算带来的数据过度集中 信息传输堵塞问题
  • 2018年最好用的5个python网站开发框架

    python作为解释型脚本语言 是一种通用的编程语言 由于python社区拥有大量的库文件 框架和其他的一些实用工具 我们可以用python完成各种各样的任务 另外 由于python的代码构成和结构就像英语句子一样自然 这种语言的学习曲线也
  • Spring(三)-IOC使用

    目录 基于XML管理bean 入门案例 引入依赖 创建类HelloWorld 创建Spring的配置文件 在Spring的配置文件中配置bean 创建测试类测试 思路 获取bean 方式一 根据id获取 方式二 根据类型获取 方式三 根据i
  • 延迟渲染到最终结果------1,2,分配渲染目标和初始化窗口(大象无形11.3.1)

    版本不同 我这里延迟渲染是FDeferredShadingSceneRenderer类 即函数 void FDeferredShadingSceneRenderer Render FRHICommandListImmediate RHICm
  • 经过两年努力,我终于进入腾讯(PCG事业群4面总结)

    前言 为什么要尽量让自己进大厂 如果毕业就进了大厂 那你将得到业内大牛的指导 以及随处可见的技术碰撞 新技术的跟进也是非常快的 在这样的环境中 你的技术成长自然是非常快的 如果自己足够努力 用不了三年 你可能也将会跟他们水平差不多 所以 明
  • c语言编译过程

    C语言的编译过程一般分为四个步骤 预处理 编译 汇编和链接 预处理 Preprocessing 预处理器会处理源代码中以 开头的预处理指令 例如 include和 define等 将它们替换为相应的内容 同时 还会删除注释和空格 将多行代码
  • qt-事件循环系统

    Qt中 如果创建的console程序 使用的是QCoreApplication对象 如果创建的是GUI程序 使用的是QApplication对象 而QApplication 继承自 QGUIApplication 最终继承QCoreAppl
  • golang的cms

    golang的cms 2019 03 06 12 53 by 轩脉刃 阅读 评论 收藏 编辑 golang的cms 说说cms cms 内容管理系统 是建站利器 它的本质是为了快速建站 cms本质是一个后台服务站 使用这个后台 能很快搭建一
  • 做区块链卡牌游戏有什么好处?

    区块链卡牌游戏是一种基于区块链技术的创新性游戏形式 它将传统的卡牌游戏与区块链技术相结合 实现了去中心化 数字化资产的交易和收集 这种新型游戏形式正逐渐在游戏行业引起了广泛的关注和热潮 本文将深入探讨区块链卡牌游戏的定义 特点以及其在未来的
  • 自己撸一个阅读类休闲app

    其实自己早就想撸一个app 因为自己一直没什么机会可以做那种好看的app 对我而言好看就是能安装在手机上 然后看着舒服的 所以也对自己所学进行一次整合 然后再次扬帆 感谢那些贡献开源api的大神 也感谢gank 主要使用的开眼的api ga
  • KafkaTemplate是如何发送消息的?

    Kafka使用KafkaTemplate发送消息 需要先实例化bean 配置如下
  • 如何在Eclipse中查看JDK以及Java框架的源码

    对于Java程序员来说 有时候是需要查看JDK或者一些Java框架的源码来分析问题的 而默认情况下 你按住Ctrl 再点击 Java本身的类库 例如ArrayList 是无法查看源码的 那么如何在Eclipse中查看JDK以及Java框架的
  • 如何计算 Node.js GC 负载

    在 Node js 中 我们关注的比较的是 CPU 负载 但是在有 GC 的语言中 GC 负载也是需要关注的一个指标 因为 GC 过高会影响我们应用的性能 本文介绍关于 GC 负载的一些内容 如何获取 GC 耗时 操作系统本身会计算每隔线程