当前位置:首页 > 数码 > 记一次性Rust内存走漏排查之旅 (记一次性游戏)

记一次性Rust内存走漏排查之旅 (记一次性游戏)

admin7个月前 (04-20)数码28

在某次继续压测环节中,咱们发现GreptimeDB的Frontend节点内存即使在恳求量颠簸的阶段也在继续下跌,直至被OOMkill。咱们判别Frontend应该是有内存走漏了,于是开启了排查内存走漏之旅。

HeapProfiling

大型名目简直无法能只经过看代码就能找到内存走漏的中央。所以咱们 首先要对程序的内存用量做统计剖析 。幸运的是,GreptimeDB经常使用的jemalloc自带heapprofiling[1],咱们也允许了导出jemalloc的profiledump文件[2]。于是咱们在GreptimeDB的Frontend节点内存到达300MB和800MB时,区分dump出了其内存profile文件,再用jemalloc自带的jeprof剖析两者内存差异(--base参数),最后用火焰图显示进去:

显然图片两边那一大长块就是始终增长的500MB内存占用了。细心观察,居然有thread关系的stacktrace。难道是创立了太多线程?繁难用ps-T-p命令看了几次Frontend节点的进程,线程数稳固在84个,而且都是预知的会创立的线程。所以线程太多这个要素可以扫除。

再继续往下看,咱们发现了很多Tokioruntime关系的stacktrace,而Tokio的task走漏也是经常出现的一种内存走漏。这个时刻咱们就要祭出另一个神器:Tokio-console[3]。

TokioConsole

TokioConsole是Tokio官网的诊断工具,输入结果如下:

咱们看到 居然有5559个正在运转的task,且绝大少数都是Idle形态!于是咱们可以确定,内存走漏出当初Tokio的task上 。如今疑问就变成了:GreptimeDB的代码里,哪里spawn了那么多的无法完结的Tokiotask?

从上图的"Location"列咱们可以看到task被spawn的中央[4]:

implRuntime{

///Spawnafutureandexecuteitinthisthreadpool

///SimilartoTokio::runtime::Runtime::spawn

pubfnspawn<F>(&self,future:F)->JoinHandle<F::Output>

F:Future+Send+'static,

F::Output:Send+'static,

self.handle.spawn(future)

接上去的义务是找到GreptimeDB里一切调用这个方法的代码。

..Default::default

经过一番看代码的细心排查,咱们终于定位到了Tokiotask走漏的中央,并在PR#1512[5]中修复了这个走漏。繁难地说,就是咱们在 某个会被经常创立的struct的结构方法中,spawn了一个可以在后盾继续运转的Tokiotask,却未能及时回收它 。关于资源治理来说,在结构方法中创立task自身并不是疑问,只需在Drop中能够顺利中断这个task即可。而咱们的内存走漏就坏在漠视了这个商定。

这个结构方法同时在该struct的Default::default方法当中被调用了,更参与了咱们找到根因的难度。

有一个很繁难的,可以用另一个struct来结构自己struct的方法,即"StructUpdateSyntax"[6]。假设struct成功了Default,咱们可以繁难地在struct的field结构中经常使用..Default::default。

假设Default::default外部有sideeffect(比如咱们本次内存走漏的要素——创立了一个后盾运转的Tokiotask),必定要特意留意: struct结构成功后, Default 创立进去的暂时struct就被摈弃了,必定要做好资源回收

例如上方这个小例子:RustPlayground[7]

implDefaultforA{

fndefault->Self{

println!("calledA::default");

#[derive(Default)]

fnnew(a:A)->Self{

//A::defaultiscalledinB::default,eventhough"a"isprovidedhere.

..Default::default

leta=A{i:1};

letb=B::new(a);

println!("{}",b.a.i);

structA的default方法是会被调用的,打印出calledA::default。

总结

•排查Rust程序的内存走漏,咱们可以用jemalloc的heapprofiling导出dump文件;再生成火焰图可直观展现内存经常使用状况。

•Tokio-console可以繁难地显示出Tokioruntime的task运转状况;要特意留意始终增长的idletasks。

•尽量不要在罕用struct的结构方法中留下有反作用的代码。

•Default只应该用于值类型struct。

参考

[1]

[2]

[3]

[4]

[5]

[6]

[7]


2GB内存能玩rust吗

这个游戏要求电脑内存达到最低4GB,推荐达到8GB内存。

记一次性Rust内存走漏排查之旅

楼主电脑只有2GB内存,明显是低了,建议考虑升级内存之后再玩,比较流畅。

如有不懂之处请追问,有帮助请采纳,谢谢.

rust内存小于10g怎么办

内存不足重开机就释放了,再说10g的内存那是很大了,好多新机器内存都只8g,足够你用了

免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。

标签: Rust

“记一次性Rust内存走漏排查之旅 (记一次性游戏)” 的相关文章

探索其优势-JavaScript开发者转向Rust的原因 (有效的探索)

探索其优势-JavaScript开发者转向Rust的原因 (有效的探索)

When it comes to web development, there are a plethora of programminglanguages to choose from. Two...

深化解析Clap命令行解析库-Rust脚手架 (深入解析)

深化解析Clap命令行解析库-Rust脚手架 (深入解析)

有感而发 最近,在和前端小同伴聊天发现,在2024年,她们都有计划入局学习的行列。毕竟前端如今太卷了,框架算是走到「走投无路」了,无非就是在原有基础上修修补补。一切他们想在新的赛道弯道超车。...

深化摸索Rust中经常使用Serde的片面指南 (深化探讨)

深化摸索Rust中经常使用Serde的片面指南 (深化探讨)

在处置HTTP恳求时,咱们总是须要在一种数据结构(可以是enum、struct等)和一种可以存储或传输并稍后重建的格局(例如JSON)之间来回转换。 Serde是一个库(crate),用于高...

在前端名目中经常使用Rust-编译为-WebAssembly (前端name)

在前端名目中经常使用Rust-编译为-WebAssembly (前端name)

前言 最近,不是放大了对关系文章的输入吗,在评论区或许私信区。有一些不同的声响说:Rust没有出路,而后...."。其实呢,看一个技术能否有须要学习的能源。想必大家的底层理由都是「一切都是向...

深化浅出把握JSON处置-如何在Rust中操作JSON (剖析深入浅出)

深化浅出把握JSON处置-如何在Rust中操作JSON (剖析深入浅出)

sonic-rs​还具备一些额外的方法来启动惰性评价和提高速度。例如,假设咱们想要一个JSON​字符串文字,咱们可以在反序列化时经常使用LazyValue​类型将其转换为一个依然带有斜杠的JSON字符...

获得代码重用性和类型安保性的长处-Rust-在-编程中经常使用泛型 (获得代码重用的方法)

获得代码重用性和类型安保性的长处-Rust-在-编程中经常使用泛型 (获得代码重用的方法)

本文的内容将触及泛型定义函数、结构体、枚举和方法,还将探讨泛型如何影响代码性能。 1.摘要 中的泛型可以让咱们为像函数签名或结构体这样的项创立定义,这样它们就可以用于多种不同的详细数据类型。...

Rust-踏上技术变革的征途-把握

Rust-踏上技术变革的征途-把握

起源|泡芙玩编程(ID:gh_23284b66d001) 前言 或者有点难学,但我还是倡导去学一学,最少要了解一下它的理念,它是如何做到它所吹的那些个性的,为什么别的言语做不到它做到了...