1

我正在尝试读取文本文件并使用Disruptor.

但是我发现CPU使用率太高了(200%,根据top命令)。

我是性能调优和线程转储分析的新手。我不知道出了什么问题。

所以我执行top -H并找到两个最高的线程(都是 99%),并找到线程转储:

"main" prio=10 tid=0x00007f54a4006800 nid=0x79ab runnable [0x00007f54a8340000]
   java.lang.Thread.State: RUNNABLE
    at java.lang.Thread.yield(Native Method)
    at com.lmax.disruptor.SingleProducerSequencer.next(SingleProducerSequencer.java:104)
    at com.lmax.disruptor.SingleProducerSequencer.next(SingleProducerSequencer.java:79)
    at com.lmax.disruptor.RingBuffer.next(RingBuffer.java:207)
    at com.xxx.xxx.connectivity.quickfixj.FixMessageReceiver.onMessage(FixMessageReceiver.java:105)
    at com.xxx.xxx.database.DatabaseService.start(DatabaseService.java:110)
    at com.xxx.xxx.database.DatabaseService.main(DatabaseService.java:168)


"pool-2-thread-1" prio=10 tid=0x00007f54a426d800 nid=0x79bc runnable [0x00007f5492a37000]
   java.lang.Thread.State: RUNNABLE
    at java.lang.Thread.yield(Native Method)
    at com.lmax.disruptor.SingleProducerSequencer.next(SingleProducerSequencer.java:104)
    at com.lmax.disruptor.SingleProducerSequencer.next(SingleProducerSequencer.java:79)
    at com.lmax.disruptor.RingBuffer.next(RingBuffer.java:207)
    at com.cimb.reporting.connectivity.jms.DatabaseEventHandler.publish2DbRingBuffer(DatabaseEventHandler.java:49)
    at com.xxx.xxx.connectivity.jms.DatabaseEventHandler.onEvent(DatabaseEventHandler.java:39)
    at com.xxx.xxx.connectivity.jms.DatabaseEventHandler.onEvent(DatabaseEventHandler.java:15)
    at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:662)

基本上这两个线程会将数据发布到 Disruptor。我Disruptor以这种方式创建:

Disruptor<TradeEvent> disruptor = new Disruptor<TradeEvent>(TradeEvent.TRADE_EVENT_FACTORY,
                properties.dbRingbufferSize(), Executors.newCachedThreadPool(),
                ProducerType.SINGLE, new BlockingWaitStrategy());

请帮助我并分析线程转储以找到高 CPU 使用率的根本原因。

4

4 回答 4

2

面临完全相同的问题:我的机器 Intel Core i3-3220 100% 的 cpu 使用率,16GB 内存,一个代理 (Xmx 2G),一个客户端 (Xmx2G),并且在环形缓冲区中没有任何消息。

快速分析显示 Thread.yield() 消耗了大约 70-80% 的 cpu。

事实证明,在我的情况下,YieldingWaitStrategy 不是一个合适的策略。所以在我的情况下,快速解决方法是将等待策略设置为 BlockingWaitStrategy:

Disruptor<MessageEvent> disruptor = new Disruptor<MessageEvent>(eventFactory, RING_BUFFER_SIZE, executor, ProducerType.SINGLE, new BlockingWaitStrategy());

更新

用于 YieldingWaitStrategy 的 JProfiler 在此处输入图像描述

于 2014-10-16T15:35:07.713 回答
1

如果确实有一些工作正在进行,那么高 CPU 利用率是可以的。即,如果有许多活动线程正在执行,Java 应用程序的净 CPU 使用率将始终处于峰值。它通常是瞬时的,即在没有任务时应该再次恢复正常。

我建议:

  1. 在固定间隔(1-2 秒)后进行多个线程转储(3-4)(可以在所有带有 jdk 的系统上使用 linux、jstack、jvisualvm、jconsole 上的 kill 命令)

  2. 执行ps -mo pid,lwp,stime,time,%cpu,%mem -C java | less. 这将在 java 应用程序的进程 ID 下列出轻量级进程。

  3. LWP获取具有最高 cpu/memory %的进程的进程 ID (作为目标)

  4. 将 lwp id 转换为十六进制值,可以使用echo "obase=16; 255" | bc

  5. 将这些十六进制 id 映射nid='some_hex_vlaue'到线程转储中,以查找对应于高 CPU 使用率的线程的详细信息。
    例如:“main”prio=10 tid=0x00007f54a4006800nid=0x79ab可运行 [0x00007f54a8340000]

现在我们知道 java 进程中具有最高资源(可用于内存/cpu%)使用率的线程/s。

我还建议将您的 jvm 进程附加到jvisualvmjconsole重现问题,这样您就可以始终监控应用程序的状态(从正常到问题重现)并拍摄快照以供参考。两者都足以执行任何 java 线程或与内存相关的分析。
http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/
http://docs.oracle.com/javase/6/docs/technotes/guides/management/jconsole.html

分析线程转储只能指向问题区域。有时它很棘手,通常影响很大,但原因和解决方法很小。实际原因通常是应用程序的编码方式。即如何管理并发。如果一个进程无限地监听而不是等待通知,由于同步问题等或系统环境/外部接口导致死锁。即磁盘或远程位置上的文件读/写,使用 ftp API 传输或可能是数据库操作等。

这是 dzone 上的一篇有用的帖子:http: //architects.dzone.com/articles/how-analyze-java-thread-dumps

希望能帮助到你。

于 2014-06-04T05:44:37.990 回答
1

这个线程有点老了,但是考虑到在最近的 JDK(fe Java 11)中,CPU 使用率暴露在线程转储中。例子:

jstack -l 5213 | grep cpu
"Reference Handler" #2 daemon prio=10 os_prio=0 cpu=4.88ms elapsed=7027.22s tid=0x0000dedewfewwewe nid=0x3456 waiting on condition  [0x00007f386cc0c000]

参考资料:找出占用 CPU 的 Java 线程

于 2021-10-26T14:41:02.027 回答
0

你应该看看java profiler。例如 VisualVM,它将实时分析您的 CPU 和 RAM 使用情况。

于 2014-06-04T05:15:26.887 回答