Jump to content
We've recently updated our Privacy Statement, available here ×
  • Fine Tuning the Java Virtual Machine


    rmiller

    Introduction

    The standard JVM arguments recommended by Jaspersoft (see the install guide) are adequate for most JasperReports Server (JRS) installations where concurrency is not high. However, with installations with high traffic requirements it is necessary to eke out as much performance as possible from the application server. This is done by fine tuning the young generation of the JVM to make garbage collection more efficient. Tuning the JVM is not an exact science, it must be done by trial and error, and since every environment is different (size and quantity of reports, size of repository, machine specifications, etc.) the tuning parameters will be slightly different for each environment. Thus, the tuning parameters described in this article should be considered a guide, not hard and fast specification.

    Garbage Collection Overview

    The Java Virtual Machine (JVM) consists of three areas where java objects live out their lives, the Permanent Generation, the Old Generation and Young Generation, collectively known as the heap. When the application server is started up most of the objects created are stored in the permanent generation and virtually all of them stay there until the application server is shut down. As objects are created while the application is used they first live in the young generation, and since most objects have a very short lifespan the are removed from the young generation during minor garbage collections. Objects that are longer lived get promoted (tenured) to the old generation. These are removed during full garbage collections, and are called stop the world collections because all activity in the JVM is stopped while the garbage collection is taking place. Since the old generation is larger and contains more objects full garbage collections are more costly in terms of time than minor collections. So, the objective of fine tuning the JVM is to ensure more minor collections and less full collections.

    The young generation consists of the eden space and two survivor spaces. Newly created objects are located in the eden space. When the eden space becomes full a garbage collection takes place and the surviving objects are copied to one of the survivor spaces. When that survivor space fills up the objects are copied to the other survivor space at the next minor collection along with any surviving objects from eden. The JVM keeps track of how many times each object is copied from one survivor space to the other and when an object reaches a certain number, called the tenuring threshold  (dynamically set by the JVM), it is promoted to the old generation. So the main objective is to size the young generation spaces to ensure that more objects are collected in the young generation before being promoted to the old generation. The sizing is done using the NewRatio and SurvivorRatio JVM options. 
     
    The NewRatio determines the size of the overall size of the young generation. For example, NewRatio=2 means that the ratio between the young and old generation is 1:2, or the young generation will be one third the size of the old generation. 
     
    The SurvivorRatio determines the size of the eden space and the two survivor spaces with respect to the total young generation size. SurvivorRatio=6 sets the ratio of the eden and a survivor space to 1:6, meaning each survivor space will one sixth the size of the eden space, or one eighth the size of the young generation (there are two survivor spaces). 
     

    Methodology

    I determined the young generation sizes by generating load using JMeter. The JMeter scripts executed six sample reports and the Supermart Dashboard with 30 concurrent virtual users. The JRS was version 5.5 installed on an Ubuntu server with Tomcat 7, JDK 7, and Postgres database. 
     
    First I ran baseline tests using the recommended JVM options with 8 GB maximum heap and 512 MB maxPermSize and ConcurrentMarkSweep garbage collection. I ran multiple tests with a one hour duration, restarting the application server before each test run. The primary metric was the average response time for all requests and I recorded the average of the average response time for each test. Then I ran tests using different values for -XX:NewRatio and -XX:SurvivorRatio, again recording the average of average response time for each test. The test results varied widely for the one hour test runs, so after determining the best tuning values for the young generation I ran a series of tests for an eight hour duration, four baseline tests and four tuned JVM tests. In the end I got a nearly 20% performance improvement using NewRatio=2 and SurvivorRatio=8.
     

    Test Results

    Test RunAverage (ms)Avg. of Avg.MaxMin% Diff.
    Baseline 8 hour 166370577366319.37 %
    Baseline 8 hour 2715    
    Baseline 8 hour 3773    
    Baseline 8 hour 4668    
    NR2 SR8 8 hour 1625568625564 
    NR2 SR8 8 hour 2581    
    NR2 SR8 8 hour 3564    
    NR2 SR8 8 hour 4503    

     


    User Feedback

    Recommended Comments

    There are no comments to display.



    Guest
    This is now closed for further comments

×
×
  • Create New...