rust - 为什么多个线程在持有 Mutex 时使用太多内存

标签 rust

下面的代码在单线程中使用约 150MB,但在 100 个线程中使用几 GB:

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let f = Arc::new(Mutex::new(Foo::new("hello")));

    let mut threads = vec![];
    for i in 0..100 {
        let f = f.clone();
        let t = thread::spawn(move || loop {
            let mut locked = f.lock().unwrap();
            *locked = Foo::new("hello");
            drop(locked);
            println!("{} reloaded", i);
            thread::yield_now();
        });
        threads.push(t);
    }

    threads.into_iter().for_each(|h| h.join().unwrap());
}

pub struct Foo {
    _data: Vec<String>,
}

impl Foo {
    fn new(s: &str) -> Foo {
        Foo {
            _data: vec![s.to_owned(); 1024 * 1024],
        }
    }
}

持有 LockGuard 时,线程应该具有独占访问权限。因此,新的 Foo 应该被分配,旧的值应该在那个时候被丢弃。因此,从多个线程调用时使用这么多内存对我来说没有任何意义。

谁能解释一下为什么这段代码占用了这么多内存?

即使有 1000 个线程,Java 中的类似代码也能保持约 200mb 的内存。

import java.util.ArrayList;
import java.util.List;

public class Foo {
    private List<String> data;

    public static void main(String[] args) {
        Foo f = new Foo();
        for (int i = 0; i < 1000; i++) {
            int n = i;
            new Thread(() -> {
                while (true) {
                    f.update();
                    System.gc();
                    System.out.println(n + " updated");
                }
            }).start();
        }
    }

    public synchronized void update() {
        data = new ArrayList<>(1024 * 1024);
        for (int i = 0; i < 1024 * 1024; i++) {
            data.add(new String("hello"));
        }
    }
}

最佳答案

所以问题出在大量的 glibc 的 malloc arenas 上, 每个竞技场都有预分配内存的缓存。检查它的简单方法是使用 MALLOC_ARENA_MAX=2 运行二进制文件,但最终解决方案取决于使用模式,有很多变量可以调整 glibc 的分配器:http://man7.org/linux/man-pages/man3/mallopt.3.html .

Java虚拟机其实也受malloc的allocator的影响。根据我的经验,有时配置 arena 的数量是合适的,以防止 docker 中的 jvm 使用大量内存。

关于rust - 为什么多个线程在持有 Mutex 时使用太多内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58110081/

相关文章:

rust - 为什么嵌套的关联类型路径被认为是模棱两可的?

rust - 实现伪裸约束

performance - 零成本抽象 : performance of for-loop vs. 迭代器

request - 如何在 Rust 中使用 tokio_proto 和 tokio_service 流式传输消息

rust - Rust 的绿色线程中的上下文切换是如何工作的?

json - 反序列化为具有枚举成员的结构

rust - 是否可以下载以前的夜间构建?

windows - 剥离 Windows 路径前缀

java - 有没有办法将结构字段作为数组访问?

Rust mut borrow 在闭包中失败