gpt4 book ai didi

java - 使用多线程使垃圾收集器使用 100% 的 CPU 时间

转载 作者:行者123 更新时间:2023-12-02 05:59:14 25 4
gpt4 key购买 nike

我逐行读取了一个 1.3GB 的文本文件。我提取并格式化内容以满足我的需要,然后再次将其保存到新的文本文件中。

本来我只是使用主线程。但提取和格式化需要大量的 CPU 时间,我想通过多线程来加速。

但这就是我的分析器显示的内容: enter image description here

当我开始使用多线程时,垃圾收集器时间增加到 100%。因此会抛出 java.lang.OutOfMemoryError: GC Overhead Limit Exed 错误。

我有一个处理单行的函数,并在 newFixedThreadPool 中执行该函数。我向池中分配一个或四个线程并不重要。

使用不同的分析器我无法找出导致问题的代码。我不明白为什么当我只使用主线程时我的 GC 为 0,0%。

有人不看代码就有想法吗?

<小时/>

更新:我尝试抽象一些代码:

A.java

ExecutorService executor = Executors.newFixedThreadPool(4);

while((line = reader.readLine()) != null) {
Runnable processLine = new Runnable() {
private String line;

private Runnable init(String line) {
this.line = line;
return this;
}

@Override
public void run() {
processLine(line); // @B.java
}
}.init(line);

executor.execute(processLine);
}

B.java

public int processLine(String line) {
String[][] outputLines = new String[x][y];
String field;

for(... x ...) {
for(... y ...) {
field = extractField(line); // @C.java
...
outputLines[x][y] = formatField(field); // @C.java
}
}

write(outputLines); // write the generated lines to BufferedWriter(s)
}

C.java

public String extractField(String line) {
if(filetype.equals("csv") {
String[] splitLine = line.split(";");

return splitLine[position];
}
...
}

public String formatField(String field) {
if(trim == true) {
field = field.trim();
}
...
}

最佳答案

我希望您的应用程序使用接近所有可用的堆空间。这将导致 JVM 越来越多的时间被用来运行垃圾收集器……徒劳地尝试回收空间。这正是 GC 开销限制设计所要处理的情况。

简而言之,要么存在存储泄漏,要么您的应用程序需要更多内存。

<小时/>

I have a function to process a single line and I execute that within a newFixedThreadPool. It doesn't matter if I assign one or four threads to the pool.

(对我来说)这强烈表明,导致问题的不是线程,而是实现多线程的方式。

<小时/>

更新

我认为您问题的根本原因是:

    ExecutorService executor = Executors.newFixedThreadPool(4);

请注意 javadoc表示该方法创建一个具有无界工作队列的执行器。

假设您的读取器线程(执行 A 代码的线程)读取和排队行的速度明显快于执行处理的线程处理、格式化和输出行的速度。

在这种情况下,会发生的情况是执行器的工作队列会变得越来越长……最终它会变得很长,以至于堆几乎充满了可访问的对象。这将导致 GC 花费很长时间来跟踪队列,并且您将得到 OOME。

如果这种情况在实践中出现,那么您的应用程序就存在内存泄漏的坏处……即使您想争辩说这实际上不是泄漏。

解决方案很简单,创建一个具有有界工作队列的执行器。您需要通过直接实例化 ThreadPoolExecutor 并提供适当配置的工作队列对象来完成此操作。

关于java - 使用多线程使垃圾收集器使用 100% 的 CPU 时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22807330/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com