一、前言

当你做的产品内存不稳定,CPU不稳定,内存在600MB-3G之内波动,cpu 在30%左右,就算你对外宣传支持可以十万设备,也不会有人相信,如果你做的产品直播推流内存一直稳定在60MB左右,cpu 在1%左右,我说带宽足够,支持1万人在线观看,客户对于这个产品也不会有所怀疑,通过一个月的努力我终于找出dotnetty 内存泄漏的问题所在,已经进行修复,以下是我现在运行的物联网平台,内存最少的是网关,有十几个协议主机运行,内存多的是业务服务并没有更新修复的dotnetty,  下面我要阐述问题所在

HttpFlv:http://demo.kayakiot.cn:281/httpflv.html  (黑衣人)

HttpFlv:http://demo.kayakiot.cn:281/httpflv1.html (大红包)

HttpFlv:http://demo.kayakiot.cn:281/httpflv2.html (鹿鼎记)

rtmp:rtmp://demo.kayakiot.cn:76/live1/livestream2   (黑衣人)

rtmp:rtmp://demo.kayakiot.cn:76/live1/livestream3   (大红包)

rtmp:rtmp://demo.kayakiot.cn:76/live1/livestream4(鹿鼎记)

注:测试服务器带宽只有8MB, httpflv  缓冲做的没有rtmp好,然后httpflv卡就多刷新几次

凯亚 (Kayak) 是什么?

凯亚(Kayak)是基于.NET8.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。

凯亚物联网平台:http://demo.kayakiot.cn:3100(用户名:fanly  密码:123456)

链路跟踪Skywalking V8:http://117.72.121.2:8080/

surging 微服务引擎开源地址:https://github.com/fanliang11/surging(后面surging 会移动到microsurging进行维护)

二、dump分析

物联网平台 1天会增长90mb内存,这些是我不能接受的,因为并没有并发访问,然后我下载dump 文件进行分析,然后用windbg分析,没有大对象的占用32767个就直接崩溃死掉了

以上没有问题,那就是线程阻塞了,输入!threads 进行分析,这么多空闲的线程(MTA),都把线程池资源耗光了,当超过最大值32767

然后再用VS可视化界面看到底有哪些线程运行,发现是dotnetty占用资源最多。那么下面来找出代码的问题

三、代码修改

dotnetty 创建线程无非就是EventExecutor,所以就把代码定位到SingleThreadEventExecutor 和LoopExecutor 类中,然后你会发现 Task.Factory.StartNew ,这个就是问题的关键了。

SingleThreadEventExecutor:

  private void Loop(object s)
{
SetCurrentExecutor(this);
//high CPU consumption tasks, running RunAllTasks in a dead loop, set TaskCreationOptions.LongRunning to avoid running out of thread pool resources. ‌‌
_ = Task.Factory.StartNew( _loopCoreAciton,CancellationToken.None, TaskCreationOptions.None, _taskScheduler);
//Loop processing is too fast and generates a large number of loopCoreAciton task schedulers.
//Using ManualResetEventSlim to process it is too late to wait, Using threadLock, LoopCore task schedulers will be released after execution
}

LoopExecutor:

      private static void Run(object state)
{
var loopExecutor = (LoopExecutor)state;
loopExecutor.SetCurrentExecutor(loopExecutor); //High CPU consumption tasks, run libuv's UV_RUN_DEFAULT mode in a loop, and set TaskCreationOptions. LongRunning can prevent thread pool resource depletion. ‌‌ ‌‌. ‌‌
_ = Task.Factory.StartNew(
executor => ((LoopExecutor)executor).StartLoop(), state,
CancellationToken.None,
TaskCreationOptions.AttachedToParent,// TaskCreationOptions.RunContinuationsAsynchronously?
loopExecutor.Scheduler);
}

然后我试试改成TaskCreationOptions.LongRunning ,然后没有用,然后再把问题定位到任务调度_taskScheduler上,发现_executor.Execute(new TaskQueueNode(this, _tasks.Take()))这段代码就是导致内存的原因,因为线程池会分配一个线程去执行,如果任务执行时间比较长,就会导致一直占用线程池线程得不到释放,所以后面我就进行修改创建新的线程进行执行,代码如下:

 internal class AloneExecutorTaskScheduler : TaskScheduler
{
private readonly IEventExecutor _executor;
private bool _started;
private readonly BlockingCollection<Task> _tasks = new();
private readonly Thread[] _threads;
protected override IEnumerable<Task>? GetScheduledTasks() => _tasks; [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override void QueueTask(Task task)
{
if (_started)
{
_tasks.Add(task);
}
else
{
// hack: enables this executor to be seen as default on Executor's worker thread.
// This is a special case for SingleThreadEventExecutor.Loop initiated task.
_started = true;
_ = TryExecuteTask(task);
}
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => false;
public AloneExecutorTaskScheduler(IEventExecutor executor,int threadCount)
{
_executor = executor;
_threads = new Thread[threadCount];
for (int index = 0; index < threadCount; index++)
{
_threads[index] = new Thread(_ =>
{
while (true)
{
_executor.Execute(new TaskQueueNode(this, _tasks.Take()));
}
});
}
Array.ForEach(_threads, it => it.Start());
} sealed class TaskQueueNode : IRunnable
{
readonly AloneExecutorTaskScheduler _scheduler;
readonly Task _task; public TaskQueueNode(AloneExecutorTaskScheduler scheduler, Task task)
{
_scheduler = scheduler;
_task = task;
} [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run() => _scheduler.TryExecuteTask(_task);
}
}

三、总结

dotnetty 最大的问题已经修复,我将会发布到nuget, 将由我发布dotnetty 1.0版本

dotnetty 内存泄漏的BUG修复了的更多相关文章

  1. 『神坑』DotNetty 内存泄漏 解决办法

    背景 近来在用 DotNetty 实现一个文件上传下载的同步服务. 其中:客户端下载服务端的文件,客户端多次请求,从服务端将文件分片下载下来,追加到本地磁盘. —— 非常简单的代码,都写了几十次了,驾 ...

  2. 【PHP内存泄漏案例】PHP对象递归引用造成内存泄漏

    [案例一] 作者:老王 如果PHP对象存在递归引用,就会出现内存泄漏.这个Bug在PHP里已经存在很久很久了,先让我们来重现这个Bug,代码如下: <?php class Foo { funct ...

  3. 引用计数gc机制使用不当导致内存泄漏

    上一篇文章找同事review了一下,收到的反馈是铺垫太长了,我尽量直入正题,哈哈 最近dbd压测时发现内存泄漏,其实这个问题去年已经暴露了,参见这篇博客[压测周].当时排查不够仔细,在此检讨下.关于d ...

  4. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(中)- IOS不为人知的Bug

    前言: 话说昨晚还是前晚,写了一篇:讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(上) 文章写到最后时,多了很多莫名奇妙的问题!!! 为了解决了这些莫名奇妙的问题,我又战斗了2 ...

  5. Android - 通过真实案例学习解内存泄漏问题,最终发现Android原生Bug

    作为一个Android新手小白,刚到新公司,最近的工作就是在学习解各类Bug.转型之初,面临各种新知识,会有压力,但是学习的过程是快乐的. 上周刚遇上一类bug,就是应用的内存泄漏问题.最终通过前辈的 ...

  6. BUG: GetDC() ReleaseDC()引起的内存泄漏

    调用CWnd::GetDC函数跟CWnd::ReleaseDC函数的代码运行时,会出现 4 个字节的内存泄漏. Microsoft 已经确认这是在本文开头部分列出的 Microsoft 产品中的缺陷. ...

  7. 【知识必备】内存泄漏全解析,从此拒绝ANR,让OOM远离你的身边,跟内存泄漏say byebye

    一.写在前面 对于C++来说,内存泄漏就是new出来的对象没有delete,俗称野指针:而对于java来说,就是new出来的Object放在Heap上无法被GC回收:而这里就把我之前的一篇内存泄漏的总 ...

  8. Android 如何有效的解决内存泄漏的问题

    前言:最近在研究Handler的知识,其中涉及到一个问题,如何避免Handler带来的内存溢出问题.在网上找了很多资料,有很多都是互相抄的,没有实际的作用. 本文的内存泄漏检测工具是:LeakCana ...

  9. python 内存泄漏调试

    Python应用程序内存泄漏的调试 Quake Lee quakelee@geekcn.org 新浪网技术(中国)有限公司 Sina Research & Development Python ...

  10. 关于Javascript的内存泄漏问题的整理稿

    写了好长时间javascript小功能模块,从来没有关注过内存泄漏问题.记得以前写C++程序的时候,内存泄漏是个严重的问题,我想是时候关注一下了.网上找了篇文章,Mark一下.原文地址:http:// ...

随机推荐

  1. JDK的SPI有什么缺陷?dubbo做了什么改进?

    JDK的SPI机制的缺点 ⽂件中的所有类都会被加载且被实例化.这样也就导致获取某个实现类的方式不够灵活,只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类.如果不想用某些实现类, ...

  2. 一文详解银河麒麟配置容器运行时及gVisor(runsc)、Kata(runv)详细指南

    容器运行时介绍 容器运行时核心概念与分类 容器运行时(Container Runtime)是管理容器生命周期(创建.启动.停止.删除)和资源隔离的核心组件,通过与操作系统内核协作实现容器化环境.根据功 ...

  3. office for mac 16.79 破解版安装教程

    教程声明 本人电脑系统:macOS Sonoma,安装版本为office for mac 16.79.本教程旨在学习分享.资源均为从网络处下载,安装破解版有风险,请自己权衡.不会安装的朋友可评论区探讨 ...

  4. 关于μkeil v5.40(keil5) 如何使用STM32(ARM)虚拟下载器进行Proteus联调

    最近我心血来潮,想用Proteus+keil5进行联调,但仔细在网上一找,全是某SDN扒下来的陈年老黑X,都快转出数字包浆了还在用,完完全全跟不上时代,也全是51单片机的版本,STM32(ARM)根本 ...

  5. 【MOOC】JS脚本|便于复制粘贴中国大学MOOC网站的测试题和选项

    文章目录 运行结果 完整代码 可复用的部分 1. 删除指定Class或Id的DOM元素 2. 在页面上添加按钮并绑定事件.添加css.class 3. 等待页面加载完成,运行异步函数 4. 选中某个D ...

  6. 【HUST】网安|操作系统实验|实验四 设备管理、文件管理

    文章目录 任务 任务1 编写一个Linux内核模块,并完成安装/卸载等操作. 1. 提示 2. 任务代码 3. 结果及说明 任务2 编写Linux驱动程序并编程应用程序测试. 1. 提示 2. 任务代 ...

  7. PC端自动化测试实战教程-4-pywinauto 操作PC端应用程序窗口 - 上篇(详细教程)

    1.简介 前几篇通过宏哥的讲解和分享,已经知道如何将PC端的应用程序启动,以及如何连接已启动的应用程序,那么启动和连接上之后呢?不用说当然是操作应用程序了,怎么操作呢?请听宏哥给你娓娓道来,所以今天主 ...

  8. Flutter跨平台发送系统通知和状态栏通知技术浅析

    @charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...

  9. TVM: VisitExpr流程分析

    TVM源码中涉及到表达式遍历的地方,一般是适用VisitExpr接口进行,这个接口设计TVM的visitor模式,具体分析可参考:TVM:visitor设计模式 基类tvm::relay::ExprF ...

  10. B1061 判断题 (15 分)

    描述 判断题的评判很简单,本题就要求你写个简单的程序帮助老师判题并统计学生们判断题的得分. 输入格式: 输入在第一行给出两个不超过 100 的正整数 N 和 M,分别是学生人数和判断题数量.第二行给出 ...