DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
View Events Video Library
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service

Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.

Monitoring and Observability for LLMs: Datadog and Google Cloud discuss how to achieve optimal AI model performance.

Automated Testing: The latest on architecture, TDD, and the benefits of AI and low-code tools.

Related

  • JVM Tuning Using jcmd
  • Inspect the Contents of the Java Metaspace Region
  • How Java Apps Litter Beyond the Heap
  • How to Modify Java Command-Line Arguments

Trending

  • Best Practices for Developing Cloud Applications
  • Modular Software Architecture: Advantages and Disadvantages of Using Monolith, Microservices and Modular Monolith
  • Choosing the Appropriate AWS Load Balancer: ALB vs. NLB
  • Cognitive AI: The Road To AI That Thinks Like a Human Being
  1. DZone
  2. Coding
  3. Languages
  4. Swiss Java Knife - A useful tool to add to your diagnostic tool-kit?

Swiss Java Knife - A useful tool to add to your diagnostic tool-kit?

Andy Overton user avatar by
Andy Overton
·
Jul. 24, 14 · Interview
Like (0)
Save
Tweet
Share
11.79K Views

Join the DZone community and get the full member experience.

Join For Free

As a support consultant at C2B2 I am always looking for handy tools that may be able to help me or my team in diagnosing our customers middleware issues. So, when I came across a project called Swiss Java Knife promising tools for 'JVM monitoring, profiling and tuning' I figured I should take a look. It's basically a single jar file that allows you to run a number of tools most of which are similar to the ones that come bundled with the JDK.

If you're interested in those tools my colleague Matt Brasier did a good introductory webinar which is available here:

http://www.c2b2.co.uk/jvm_webinar_video

Downloading

Firstly I downloaded the latest jar file from github:

https://github.com/aragozin/jvm-tools

The source code is also available but for the purposes of this look into what it can offer the jar will suffice.

What does it offer?

Swiss Java Knife offers a number of commands:

jps - Similar to the jps tool that comes with the JDK.
ttop - Similar to the linux top command.
hh - Similar to running the jmap tool that comes with the JDK with the -histo option.
gc - Reports information about GC in real time.
mx - Allows you to do basic operations with MBeans from the command line.
mxdump - Dumps all MBeans of the target java process to JSON.

Testing

In order to test out the commands that are available I set up a Weblogic server and deployed an app containing a number of servlets that have known issues. These are then called via JMeter to show certain server behaviour:

  • excessive Garbage Collection
  • high CPU usage
  • a memory leak


Finding the process ID

Normally to find the process ID I'd use the jps command that comes with the JDK.

Swiss Java Knife has it's own version of the jps command so I tried that instead.

Running the command:

java -jar sjk-plus-0.1-2013-09-06.jar jps

gives the following output:

5402org.apache.derby.drda.NetworkServerControl start
3250weblogic.Server
4032./ApacheJMeter.jar
3172weblogic.NodeManager -v
5427weblogic.Server
6523sjk-plus-0.1-2013-09-06.jar jps
Which is basically the same as running the jps command with the -l option.
There are a couple of additions where you can add filter options allowing you to pass in wild cards to match process descriptions or JVM system properties but overall it adds very little to the standard jps tool.
jps -lv will generally give you everything you need.
OK, so now we've got the process ID of our server we can start to look at what is going on. First of all, lets check garbage collection.
Checking garbage collection

OK. Now this one looks more promising. Swiss Java Knife has a command for collecting real time GC statistics. Let's give it a go.

So, running the following command without my dodgy servlet running should give us a 'standard' reading:

java -jar sjk-plus-0.1-2013-09-06.jar gc -p 3016
[GC: PS Scavenge#10471 time: 6ms interval: 113738ms mem: PS Survivor Space: 0k+96k->96k[max:128k,rate:0.84kb/s] PS Old Gen: 78099k+0k->78099k[max:349568k,rate:0.00kb/s] PS Eden Space: 1676k-1676k->0k[max:174464k,rate:-14.74kb/s]]
[GC: PS MarkSweep#10436 time: 192ms interval: 40070ms mem: PS Survivor Space: 96k-96k->0k[max:128k,rate:-2.40kb/s] PS Old Gen: 78099k+7k->78106k[max:349568k,rate:0.19kb/s] PS Eden Space: 0k+0k->0k[max:174400k,rate:0.00kb/s]]

PS Scavenge[ collections: 31 | avg: 0.0057 secs | total: 0.2 secs ]
PS MarkSweep[ collections: 9 | avg: 0.1980 secs | total: 1.8 secs ]

OK. Looks good. Useful to be able to get runtime GC info without having to rely on GC logs which are often not available.

After running my dodgy servlet (containing a number System.gc() calls) we see the following:

[GC: PS Scavenge#9787 time: 5ms interval: 38819ms mem: PS Survivor Space: 0k+64k->64k[max:192k,rate:1.65kb/s] PS Old Gen: 78062k+0k->78062k[max:349568k,rate:0.00kb/s] PS Eden Space: 204k-204k->0k[max:174336k,rate:-5.28kb/s]]
[GC: PS MarkSweep#10200 time: 155ms interval: 112488ms mem: PS Survivor Space: 64k-64k->0k[max:192k,rate:-0.57kb/s] PS Old Gen: 78071k+0k->78071k[max:349568k,rate:0.00kb/s] PS Eden Space: 0k+0k->0k[max:174336k,rate:0.00kb/s]]

PS Scavenge[ collections: 666 | avg: 0.0046 secs | total: 3.1 secs ]
PS MarkSweep[ collections: 689 | avg: 0.1588 secs | total: 109.4 secs ]

A big difference and although not a particularly realistic scenario it's certainly a useful tool for being able to quickly view runtime GC info.

Next up we'll take a look at CPU usage.

Checking CPU usage

Swiss Java Knife has a command that works in a similar way to the linux top command which displays the top CPU processes.

Running the following command should give us the top 10 CPU processes when running normally:

java -jar sjk-plus-0.1-2013-09-06.jar ttop -n 10 -p 5427 -o CPU

2014-03-11T08:56:33.120-0700 Process summary
  process cpu=2.21%
  application cpu=0.67% (user=0.30% sys=0.37%)
  other: cpu=1.54%
  heap allocation rate 245kb/s
[000001] user= 0.00% sys= 0.00% alloc=     0b/s - main
[000002] user= 0.00% sys= 0.00% alloc=     0b/s - Reference Handler
[000003] user= 0.00% sys= 0.00% alloc=     0b/s - Finalizer
[000004] user= 0.00% sys= 0.00% alloc=     0b/s - Signal Dispatcher
[000010] user= 0.00% sys= 0.00% alloc=     0b/s - Timer-0
[000011] user= 0.00% sys= 0.01% alloc=    96b/s - Timer-1
[000012] user= 0.00% sys= 0.01% alloc=    20b/s - [ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'
[000013] user= 0.00% sys= 0.00% alloc=     0b/s - weblogic.time.TimeEventGenerator
[000014] user= 0.00% sys= 0.04% alloc=   245b/s - weblogic.timers.TimerThread
[000017] user= 0.00% sys= 0.00% alloc=     0b/s - Thread-7

So far so good, minimal CPU usage. Now I'll run my dodgy servlet and run it again:

Hmmm, not so good:

Unexpected error: java.lang.IllegalArgumentException: Comparison method violates its general contract!

Try once again and we get the following:

2014-03-11T09:00:10.625-0700 Process summary
  process cpu=199.14%
  application cpu=189.87% (user=181.57% sys=8.30%)
  other: cpu=9.27%
  heap allocation rate 4945kb/s
[000040] user=83.95% sys= 2.82% alloc=     0b/s - [ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'
[000038] user=93.71% sys=-0.44% alloc=     0b/s - [ACTIVE] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'
[000044] user= 3.90% sys= 4.91% alloc= 4855kb/s - RMI TCP Connection(5)-127.0.0.1
[000001] user= 0.00% sys= 0.00% alloc=     0b/s - main
[000002] user= 0.00% sys= 0.00% alloc=     0b/s - Reference Handler
[000003] user= 0.00% sys= 0.00% alloc=     0b/s - Finalizer
[000004] user= 0.00% sys= 0.00% alloc=     0b/s - Signal Dispatcher
[000010] user= 0.00% sys= 0.00% alloc=     0b/s - Timer-0
[000011] user= 0.00% sys= 0.04% alloc=  1124b/s - Timer-1
[000012] user= 0.00% sys= 0.00% alloc=     0b/s - [STANDBY] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'

So, the CPU usage is now through the roof (as expected).

The main issue with this is that similar to the jps command it doesn't really offer much more than the top command. It also threw the exception above many times when trying to run commands ordered by CPU.

Overall, it doesn't really add much to the command already available and unexpected errors are never good.

Finally, we'll take a look at memory usage.

Checking memory usage

For checking memory usage Swiss Java Knife has a tool called hh which it claims is an extended version of jmap -histo. For those not familiar with jmap, it's another of the tools that comes with the JDK which prints shared object memory maps or heap memory details for a process.

So, first of all I run my JMeter test that repeatedly calls my dodgy servlet. This time one that allocates multiple byte arrays each time it's called to simulate a memory leak.

Although it claims to be an extended version of jmap -histo the only real addition is the ability to state how many buckets to view but this can be easily achieved by piping the output of jmap -histo through head. Aside from that the output is virtually identical.

Output from jmap:

 num     #instances         #bytes  class name
----------------------------------------------
   1:         42124      234260776  [B
   2:        161472       24074512  <constMethodKlass>
   3:        161472       21970928  <methodKlass>
   4:         12853       15416848  <constantPoolKlass>
   5:         12853       10250656  <instanceKlassKlass>
   6:         84735        9020400  [C
   7:         10896        8943104  <constantPoolCacheKlass>
   8:         91873        2939936  java.lang.String
   9:         14021        1675576  java.lang.Class
  10:         10311        1563520  [Ljava.lang.Object;

  Output from sjk:

  java -jar sjk-plus-0.1-2013-09-06.jar hh -n 10 -p 5427
    1:         56626      386286072  [B
   2:        161493       24076192  <constMethodKlass>
   3:        161493       21973784  <methodKlass>
   4:         12850       15409912  <constantPoolKlass>
   5:         12850       10249384  <instanceKlassKlass>
   6:         10891        8936672  <constantPoolCacheKlass>
   7:         83336        8577720  [C
   8:         90525        2896800  java.lang.String
   9:         14018        1675264  java.lang.Class
  10:          9819        1579400  [Ljava.lang.Object;
Total        996089      500086120

The only other tools available are the commands mxdump and mx which allow access to MBean attributes and operations.

However, trying to run either of these resulted in a Null pointer exception. 

At this point I would generally download the code and start to poke about but by now I'd seen enough.

Conclusion

Although a nice idea it's very limited in what it offers. Under the covers it uses the Attach API so requires the JDK and not just the JRE in order to run so the majority of tools available are already provided with the standard JDK. There are a few additions to those tools but nothing that really makes it worthwhile using this instead.

The only tool I could see myself using would be the real-time GC data gathering tool but this would only be of use where GC logs were unavailable and no other monitoring tools were available.

The number of errors seen when running basic commands was also a concern, although this is just a project on github not a commercial offering and doesn't appear to be a particularly active project.

So, a useful tool to add to your diagnostic tool-kit? Not in my opinion. It's certainly an interesting idea and with further work could be useful but for now I'd stick with the tools that are already available.
Java (programming language) Knife garbage collection Command (computing)

Published at DZone with permission of Andy Overton. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • JVM Tuning Using jcmd
  • Inspect the Contents of the Java Metaspace Region
  • How Java Apps Litter Beyond the Heap
  • How to Modify Java Command-Line Arguments

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: