下面的代码在单线程中使用〜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
应分配新值,而应丢弃旧值。因此,对我来说,从多个线程中调用这么多的内存正在使用,这没有任何意义。
谁能解释为什么此代码使用了这么多的内存?
Java中的类似代码即使有1000个线程也可以将内存保持在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领域众多,每个领域都有预分配内存的缓存。检查它是否是使用二进制运行的简单方法MALLOC_ARENA_MAX=2
,但是最终解决方案取决于使用模式,有很多变量可以调整glibc的分配器:http : //man7.org/linux/man-pages/man3/mallopt.3.html。
Java虚拟机实际上也受malloc的分配器影响。从我的经验来看,配置一些竞技场以防止在docker内部使用jvm占用大量内存是合适的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句