Memory 无法在异步任务中释放动态内存
我们的Rust应用程序似乎有内存泄漏,我将问题归结为下面的代码示例。我还是看不出问题出在哪里 我的期望是,在(500000+1)的第条消息中,应用程序的内存将恢复到较低的水平。相反,我认为:Memory 无法在异步任务中释放动态内存,memory,rust,async-await,rust-tokio,Memory,Rust,Async Await,Rust Tokio,我们的Rust应用程序似乎有内存泄漏,我将问题归结为下面的代码示例。我还是看不出问题出在哪里 我的期望是,在(500000+1)的第条消息中,应用程序的内存将恢复到较低的水平。相反,我认为: 在发送500000条消息之前,内存使用量为124KB 发送500000条消息后,内存使用量攀升至27MB 发送500000+1消息后,内存使用率降至15.5MB 在尝试了很多东西之后,我找不到15.5MB的隐藏位置。释放内存的唯一方法是终止应用程序。Valgrind未检测到任何内存泄漏。如果能找到一个解
- 在发送500000条消息之前,内存使用量为124KB
- 发送500000条消息后,内存使用量攀升至27MB
- 发送500000+1消息后,内存使用率降至15.5MB
- 如果我删除
self.items.push(数据)代码>内存使用不会增加,所以我认为这不是发送方/接收方的问题
- 在
弧中包装
没有明显的记忆差异项目:Vec
struct处理器{
项目:Vec,
}
嵌入式处理器{
pub fn new()->Self{
处理机{
项目:Vec::new(),
}
}
发布异步fn任务(mut self,mut receiver:receiver){
而让一些(数据)=receiver.next().等待{
self.items.push(数据);
如果self.items.len()大于500000{
{
std::mem::replace(&mut self.items,Vec::new());
}
println!(“空项数组”);
}
}
println!(“处理器任务在5秒内关闭”);
东京:时间:延迟(持续时间:从秒(5))。等待;
}
}
完整的可运行示例
use std::time::Duration;
use tokio::stream::StreamExt;
use tokio::runtime::Runtime;
use tokio::sync::mpsc::{channel, Receiver, Sender};
struct Processor {
items: Vec<String>,
}
impl Processor {
pub fn new() -> Self {
Processor {
items: Vec::new(),
}
}
pub async fn task(mut self, mut receiver: Receiver<String>) {
while let Some(data) = receiver.next().await {
self.items.push(data);
if self.items.len() > 500000 {
{
std::mem::replace(&mut self.items, Vec::new());
}
println!("Emptied items array");
}
}
println!("Processor task closing in 5 seconds");
tokio::time::delay_for(Duration::from_secs(5)).await;
}
}
pub fn main() {
{
let mut runtime: Runtime = tokio::runtime::Builder::new()
.threaded_scheduler()
.core_threads(1)
.enable_all()
.build()
.expect("Failed to build runtime");
let (mut sender, receiver) = channel(1024);
let p = Processor::new();
runtime.spawn(async move {
println!("Before send, waiting 5 seconds");
tokio::time::delay_for(Duration::from_secs(5)).await;
for i in 0..500000 {
sender.send("Hello".to_string()).await;
}
println!("Sent 500,000 items, waiting 5 seconds");
tokio::time::delay_for(Duration::from_secs(5)).await;
sender.send("Hello".to_string()).await;
println!("Send message to clear items");
tokio::time::delay_for(Duration::from_secs(3)).await;
println!("Closing sender in 5 seconds");
tokio::time::delay_for(Duration::from_secs(5)).await;
});
runtime.block_on(async move {
{
p.task(receiver).await;
}
println!("Task is done, waiting 5 seconds");
tokio::time::delay_for(Duration::from_secs(5)).await;
});
}
println!("Runtime closed, waiting 5 seconds");
std::thread::sleep(Duration::from_secs(5));
}
使用std::time::Duration;
使用tokio::stream::StreamExt;
使用tokio::runtime::runtime;
使用tokio::sync::mpsc::{通道、接收器、发送器};
结构处理器{
项目:Vec,
}
嵌入式处理器{
pub fn new()->Self{
处理机{
项目:Vec::new(),
}
}
发布异步fn任务(mut self,mut receiver:receiver){
而让一些(数据)=receiver.next().等待{
self.items.push(数据);
如果self.items.len()大于500000{
{
std::mem::replace(&mut self.items,Vec::new());
}
println!(“空项数组”);
}
}
println!(“处理器任务在5秒内关闭”);
东京:时间:延迟(持续时间:从秒(5))。等待;
}
}
pub fn main(){
{
让mut运行时:runtime=tokio::runtime::Builder::new()
.threaded_调度程序()
.核心螺纹(1)
.enable_all()
.build()
.expect(“构建运行时失败”);
let(mut发送方,接收方)=信道(1024);
设p=Processor::new();
生成(异步移动){
println!(“发送前,等待5秒”);
东京:时间:延迟(持续时间:从秒(5))。等待;
因为我在0..500000{
sender.send(“Hello.to_string())。等待;
}
println!(“发送500000个项目,等待5秒”);
东京:时间:延迟(持续时间:从秒(5))。等待;
sender.send(“Hello.to_string())。等待;
println!(“发送消息以清除项目”);
东京:时间:延迟(持续时间:从秒(3))。等待;
println!(“在5秒内关闭发送方”);
东京:时间:延迟(持续时间:从秒(5))。等待;
});
runtime.block_on(异步移动{
{
p、 任务(接收者)。等待;
}
println!(“任务完成,等待5秒”);
东京:时间:延迟(持续时间:从秒(5))。等待;
});
}
println!(“运行时关闭,等待5秒”);
std::thread::sleep(持续时间::from_secs(5));
}
Cargo.toml
[package]
name = "mem-help"
version = "0.1.0"
authors = ["Patrick Lorio <dev@plorio.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
futures = "0.3.1"
tokio = { version = "0.2.6", features = ["full"] }
[软件包]
name=“mem帮助”
version=“0.1.0”
作者=[“Patrick Lorio”]
edition=“2018”
#请参阅上的更多关键点及其定义https://doc.rust-lang.org/cargo/reference/manifest.html
[依赖关系]
futures=“0.3.1”
东京={version=“0.2.6”,功能=[“full”]}
泄漏是一种随着时间的推移而增长的现象,您似乎在描述这种情况,不是吗?此外,您不使用任何可能导致程序泄漏内存的东西。所以1。你为什么认为这不正常?2.如果泄漏是真的,那肯定不是你的错,所以这可能是我更大的应用程序中的一个错误,内存增长到溢出的程度(16千兆)。我的期望是,在执行std::mem::replace(&mut self.items,Vec::new())之后代码>内存应返回到与推送向量之前类似的级别。我可能会错过使用异步等待。如果有库错误,任何缩小它的提示都将不胜感激。值得测试,因为我说过这段代码不应该泄漏任何内存,async是非常新的,所以不要犹豫,把它作为错误发布在tokio存储库上,无论如何,我建议您阅读。这是关注点C,但锈与它有许多共同的行为。这应该可以更清楚地解释空闲内存是如何工作的。在Linux上,我建议您通过valgrind--tool=massif
查看您的应用程序:这是一个内存分析器,它将定期输出内存使用情况的快照,对于每个快照,有多少使用情况是由于特定的堆栈跟踪造成的。这将立即允许您停止应用程序的哪个部分正在分配16G(未释放)。您可以尝试设置MALLOC\u ARENA\u MAX=2
然后运行代码吗?如果问题在那之后消失了,那么这是一个重复。泄漏是一个随着时间的推移而增长的事情,你似乎描述了不是这样吗?而且,你不需要使用任何与c有关的东西