Reputation: 2222
I'm trying to read text file and insert into database with Disruptor
.
But I find that the CPU usage is too high (200%, according to top
command).
I'm new to performance tuning and thread dump analysis. I don't know what's going wrong.
So I execute top -H
and find the two highest threads (both are 99%), and find the thread dump:
"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)
Basically these two threads are going to publish data to Disruptor. I create Disruptor
in this way:
Disruptor<TradeEvent> disruptor = new Disruptor<TradeEvent>(TradeEvent.TRADE_EVENT_FACTORY,
properties.dbRingbufferSize(), Executors.newCachedThreadPool(),
ProducerType.SINGLE, new BlockingWaitStrategy());
Please help me and analyze the thread dump to find the root cause of high CPU usage.
Upvotes: 2
Views: 14373
Reputation: 4338
This thread is a bit old however consider that in most recent JDK (f.e. Java 11) the CPU usage is exposed in the Thread Dump. Example:
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]
References: Find which Java Thread is hogging your CPU
Upvotes: 1
Reputation: 6802
High CPU utilization is ok if there is actually some work in progress. i.e. if there are many live threads performing, the net CPU usage for java application will always be at its peak. It is usually instantaneous, i.e. should get normal again when there are no tasks.
I would suggest to:
Take multiple thread dumps (3-4) after a fix interval (1-2 seconds) (can use kill command on linux, jstack , jvisualvm, jconsole on all systems with jdk)
execute
ps -mo pid,lwp,stime,time,%cpu,%mem -C java | less
. This will list the lightweight processes under the java application's process id.Get the process ids of the processes
LWP
with highest cpu/memory % (as targeted)convert the lwp ids in to hexadecimal values, can use
echo "obase=16; 255" | bc
Map these hex ids as
nid='some_hex_vlaue'
in the thread dump to find the details of thread corresponding to high cpu usage.
e.g: "main" prio=10 tid=0x00007f54a4006800nid=0x79ab
runnable [0x00007f54a8340000]Now we know the thread/s within the java process with highest resource(can be used for both memory/cpu%) usage.
I would also recommend to attach your jvm process to jvisualvm
or jconsole
and reproduce the problem, this way you can monitor your application’s state at all the time (from normal to issue reproduction) and take snapshots for reference.
Both are good enough to perform any java threads or memory related profiling.
http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/
http://docs.oracle.com/javase/6/docs/technotes/guides/management/jconsole.html
Analyzing thread dumps can only point to the problem areas. At times its tricky, usually with high impact, but the cause and fix will be small. Actual cause would usually be either the way application is coded. i.e. How concurrency is managed. If a process is listening infinitely instead of waiting for notification, deadlocks due to synchronization issues etc or the system environment/external interfaces. i.e. file r/w on disk or remote locations, transfer using a ftp APIs or may be db operations etc.
Here is one useful post at dzone: http://architects.dzone.com/articles/how-analyze-java-thread-dumps
Hope it helps.
Upvotes: 1
Reputation: 1629
Faced exactly the same problem: 100% cpu usage on my machine Intel Core i3-3220 with 16GB memory with one broker (Xmx 2G), one client (Xmx2G) and without any message in a ringbuffer.
Quick profiling shows that Thread.yield() consumes about 70-80% of cpu.
It is turned out the YieldingWaitStrategy is not a proper strategy in my case. So in my case quick fix was to set the wait strategy into BlockingWaitStrategy:
Disruptor<MessageEvent> disruptor = new Disruptor<MessageEvent>(eventFactory, RING_BUFFER_SIZE, executor, ProducerType.SINGLE, new BlockingWaitStrategy());
UPDATE
JProfiler for YieldingWaitStrategy
Upvotes: 3
Reputation: 894
You should have a look at a java profiler. For example VisualVM, which will analyze your CPU and RAM use in real time.
Upvotes: 0