【问题标题】:High CPU usage by unknown process in multithreading多线程中未知进程的高 CPU 使用率
【发布时间】:2017-04-26 21:52:27
【问题描述】:

我们的服务器配备 35gb 内存和 Intel® Xeon(R) E5-1620 0 @ 3.60GHz × 8 CPU。我正在运行一个用 akka 演员设计并用 scala 编写的多线程程序。在程序中,有 4 个演员有任务:

1) 使用 Scala 的 BufferedSource 和迭代器从文件中延迟读取,

2) 标记句子,

3) 计算给定窗口大小的单字和双字词频率,并将它们放入一个映射(一个映射用于单个单词 [String, Int],一个用于元组单词 [WordTuple,Int),

4) 将返回的 hasmaps 合并到一个 hashmap 中,当所有行从文件中读取并将它们写入文件时。

我的自定义jvm设置如下:

-Xms34g

-Xmx34g

-XX:ReservedCodeCacheSize=240m

-XX:+UseParallelGC

-XX:ParallelGCThreads=4

-XX:NewSize=12g

-XX:SoftRefLRUPolicyMSPerMB=50

-ea

-Dsun.io.useCanonCaches=false

-Djava.net.preferIPv4Stack=true

-XX:+HeapDumpOnOutOfMemoryError

-XX:-OmitStackTraceInFastThrow

-Dawt.useSystemAAFontSettings=lcd

-Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine

-verbose:gc

-XX:+PrintGCDetails

-Xloggc:gc.log

我的application.conf如下:

systemParameters {
  linesPerActor = 5
  windowSize = 6
  threadPoolSize = 5
}


akka.actor.deployment {

  /wordTokenizerRouter {
    router = round-robin-pool
    nr-of-instances = 5
  }

  /frequencyCalculatorRouter {
    router = round-robin-pool
    nr-of-instances = 5
  }
}

问题:

我正在处理一个大小为 15gb 的文本文件。程序开始工作,过了一段时间,比如说 2 个小时,那些标记化、计算操作几乎不起作用,没有操作可以执行。需要 300 毫秒的操作开始需要 100000 秒。但是所有处理器的 cpu 使用率都是 %100。我尝试使用 jvisualvm 对其进行移动,但采样器无法处理如此高的 cpu 使用率,因此我无法确定哪个进程正在使 cpu %100。我从 jvisualvm 检查 gc 活动,大部分时间它使用大约 %10 cpu。那么,我的程序可能有什么问题,哪个进程可能正在使用所有的 cpu?

以下是 jvisualvm 的一些屏幕截图,当程序中的操作停止但 cpu 使用率为 %100 时:

Garbage collector status screenshot

Overall status screenshot

希望我解释清楚。提前感谢您的回答。

【问题讨论】:

    标签: multithreading scala jvm nlp large-text


    【解决方案1】:

    我会研究几个方面。

    1. 您的堆看起来已满,包括老年代。另一个提示:在 8 小时 20 分钟的运行时间中,您的应用程序在 olg generation GC 中花费了 5 小时 45 分钟。当你堆满时,它会一个接一个地触发完整的 GC。 使用并行 GC,这将在完整 GC 期间使用所有内核。 看看你的 gc.log,看看有多少次完整的 GC 被触发。
    2. 在 CPU 负载期间,创建一些线程转储。您可以使用 VisualVM' 或 `jstack' 命令。在 Visual VM 中,它位于“线程”选项卡上的“线程转储”。查看堆栈转储并查找“可运行”线程,这些线程不在某些阻塞/IO API 中。看看他们在做什么。

    如果它在垃圾收集上花费时间。我会进行堆转储并分析所持有的内存。您也可以在 VisualVm 的 Monitor 选项卡中进行堆转储,并在那里进行粗略分析。

    【讨论】:

    • 正如我现在观察到的,随着时间的推移,垃圾收集的频率正在增加,以至于 5 秒运行应用程序之后是 10 秒垃圾收集。随着时间的推移,这个时间段越来越窄。现在,我观察到更具体的问题,垃圾收集器运行无法清理整个空间,它只是清理了一点未使用的引用,应用程序堆又满了。下面是一个截图证明:imgur.com/0NbZelt 和另一个使用高 cpu 的 gc:imgur.com/a/YSrsw 所以,应用程序的工作量减少了。
    • 垃圾回收在运行时无法清除所有未使用的引用的原因是什么?
    • 您的应用程序持有对对象的引用,因此 GC 无法收集。如果你真的需要它,找出那些拥有这些参考的东西。比如,进行堆转储。那么堆中有哪些实例。使用“查找根”找出引用是如何保持活动状态的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多