我的同事给我这样的代码片段:
public class Main1 {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable runnable = () -> {
try {
// business logic
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(LocalDateTime.now().toString() + ":" + Thread.currentThread().getName());
};
for (int i = 0; i < 100000; i++) {
executorService.execute(runnable);
}
System.in.read();
}
}
在上面的代码中,创建100000可运行实例。当我运行此代码时,我可以看到JVisualVM中的堆空间增加了,但是100000可运行实例的内存大小几乎没有变化。我的JVM选择是-Xms20m -Xmx20m -XX:MaxTenuringThreshold = 1。在macOS High Sierra版本10.13.6上,Java版本是1.8.0_151。线程池中的所有线程都处于睡眠状态,那么为什么堆距离增加了?创建了什么对象?
答案 0 :(得分:2)
注意:大多数垃圾是由VisualVM本身监视JVM所创建的。它使用效率很低的Java序列化。减少垃圾产生的最好方法是缩短轮询间隔。 (或者使用JMC或YourKit这样的配置文件)
创建任务使用内存,添加到工作队列的每个节点都使用内存。一种更快捷,更有效的方法是IntStream
public class Main {
static void doWork(int task) {
try {
System.out.println("starting " + task);
// business logic
Thread.sleep(10000);
System.out.println("... finished " + task);
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
public static void main(String[] args) {
IntStream.range(0, 100_000)
.parallel()
.forEach(Main::doWork);
}
}
通过将任务分解为可用数量的处理器,这将使用相同数量的内存,而不考虑任务的数量(它为您拥有的每个处理器仅创建两个实际任务)
答案 1 :(得分:1)
您正在创建10.000个可运行实例,而由于您的线程池,一次只能执行3个线程。它会创建大量无法运行的Runnable实例。
尝试增加线程池大小,或减少必须执行的线程数。