HomeAboutArchivesTools & ResourcesSupport me
Hi! 👋 I'm Szymon

I help you become a better software developer.

  • 1.15kFollowers
  • 2.36kSubscribers
  • 110Followers
  • 30.2kReputation

Latest posts from the Learning Java

GraalVM and heap size of the native image - how to set it?
Installing GraalVM EE 1.0.0-RC14 with SDKMAN!
Java 8 type inference in generic methods chain call - what mi...
Divide a list to lists of n size in Java 8
More

Popular categories

  • Groovy Cookbook28
  • Jenkins Pipeline Cookbook9
  • Programmer's Bookshelf6
  • Micronaut Cookbook4
  • Ratpack Cookbook4
  • Learning Java4
  • jq cookbook3
  • How to3
  • Blog Reports2

Don't miss anything - join my newsletter

Additional materials and updates for subscribers. No spam guaranteed.
Unsubscribe at any time.

Did you like this article?

Spread the !
  • ☕️
  1. e.printstacktrace.blog
  2. Learning Java

GraalVM and heap size of the native image - how to set it?

  • April 2, 2019
  • 6 min. read
  • 0 Comments

In this short blog post, I would like to show you how to set a heap size of the application executed from the native image generated with GraalVM. We will also take a quick look at the effects caused the maximum heap size change.

GraalVM heap size setting

If you want to set up the maximum heap size of the application executed from the native image, use  -Xmx{n} command line option. For instance, if we want to set up a maximum heap size to 128 MB we can do the following:

Listing 1. Setting maximum heap size to 128 MB
./your-native-image-executable -Xmx128m
This blog post is published when the most recent version of GraalVM is 1.0.0-RC14.

An example

In the following example, I will use the native image I’ve created for my demo Ratpack application. The only difference is that this time I have configured this application to use a single thread for handling event loop events. (HTTP requests in particular.)

In the following example I also use -XX:+PrintGC, -XX:+PrintGCTimeStamps, -XX:+VerboseGC and +XX:+PrintHeapShape flags to log verbose garbage collector activity to the console.

For testing purpose, I’m going to execute 200 parallel requests, repeated 100 times, so our application will have to handle 20,000 requests in total. I use siege [1] tool to execute those requests. Firstly, let’s do this test with the application executed without specifying the heap size. However, what is the default maximum heap size? You can find it out using GraalVM polyglot launcher for instance:

Listing 2. Finding the default maximum heap size
$ polyglot --native --help:vm | grep HeapSize
  --vm.XX:MaximumHeapSizePercent=80            The maximum heap size as percent of physical memory.
  --vm.Xmx<value>                              Sets the maximum size of the heap, in bytes. Default: MaximumHeapSizePercent * physical memory.

As you can see, it’s set to 80% of the physical memory. In my case it is something around 12.29 GB. Let’s run the application.

Listing 3. Running Ratpack application with the default max heap size
$ ./ratpack-graalvm-demo -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+VerboseGC +XX:+PrintHeapShape
[main] INFO ratpack.server.RatpackServer - Starting server...
[main] INFO ratpack.server.RatpackServer - Building registry...
[main] INFO ratpack.server.RatpackServer - Ratpack started for http://localhost:5050

We can execute 20,000 requests now.

Listing 4. Executing 20k requests using siege
$ siege -c 200 -r 100 http://localhost:5050/
...
HTTP/1.1 200     0.01 secs:      53 bytes ==> GET  /
HTTP/1.1 200     0.01 secs:      53 bytes ==> GET  /
HTTP/1.1 200     0.00 secs:      53 bytes ==> GET  /

Transactions:		       20000 hits
Availability:		      100.00 %
Elapsed time:		        4.31 secs
Data transferred:	        1.01 MB
Response time:		        0.03 secs
Transaction rate:	     4640.37 trans/sec
Throughput:		        0.23 MB/sec
Concurrency:		      143.19
Successful transactions:       20000
Failed transactions:	           0
Longest transaction:	        3.14
Shortest transaction:	        0.02

Let’s take a look at the console where the application is running.

$ ./ratpack-graalvm-demo -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+VerboseGC +XX:+PrintHeapShape
[main] INFO ratpack.server.RatpackServer - Starting server...
[main] INFO ratpack.server.RatpackServer - Building registry...
[main] INFO ratpack.server.RatpackServer - Ratpack started for http://localhost:5050
[Heap policy parameters:
  YoungGenerationSize: 268435456
      MaximumHeapSize: 13193507600
      MinimumHeapSize: 536870912
     AlignedChunkSize: 1048576
  LargeArrayThreshold: 131072]
[[36323 msec:  GC: before  epoch: 1  cause: CollectOnAllocation.Sometimes]
[36333 msec: Incremental GC (CollectOnAllocation.Sometimes) 261172K->17403K, 0.0105428 secs]
 [36333 msec:  GC: after   epoch: 1  cause: CollectOnAllocation.Sometimes  policy: by time: 50% in incremental collections  type: incremental
  collection time: 10542877 nanoSeconds]]

As you can see, there was no much activity from the garbage collector. Here what does the memory consumption of this process looks like:

$ ps ef -o command,vsize,rss,%mem,size | grep ratpack | head -n 1
 \_ ./ratpack-graalvm-demo  525924 280148  1.7 307328

It consumed 280 MB RSS. Is it much? Maybe. Let’s run the same application with -Xmx64m and check if it makes any difference.

Listing 5. Running Ratpack application with max heap size set to 64 MB
$ ./ratpack-graalvm-demo -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+VerboseGC +XX:+PrintHeapShape -Xmx64m
[main] INFO ratpack.server.RatpackServer - Starting server...
[main] INFO ratpack.server.RatpackServer - Building registry...
[main] INFO ratpack.server.RatpackServer - Ratpack started for http://localhost:5050

Application started. It’s time to execute the same amount of requests.

Listing 6. Executing 20k requests using siege
$ siege -c 200 -r 100 http://localhost:5050/
...
HTTP/1.1 200     0.01 secs:      53 bytes ==> GET  /
HTTP/1.1 200     0.01 secs:      53 bytes ==> GET  /
HTTP/1.1 200     0.00 secs:      53 bytes ==> GET  /

Transactions:		       20000 hits
Availability:		      100.00 %
Elapsed time:		        3.86 secs
Data transferred:	        1.01 MB
Response time:		        0.03 secs
Transaction rate:	     5181.35 trans/sec
Throughput:		        0.26 MB/sec
Concurrency:		      152.01
Successful transactions:       20000
Failed transactions:	           0
Longest transaction:	        3.09
Shortest transaction:	        0.01

This time the garbage collector was much more active - here is the console log generated while the application was handling 20k requests:

$ ./ratpack-graalvm-demo -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+VerboseGC +XX:+PrintHeapShape -Xmx64m
[main] INFO ratpack.server.RatpackServer - Starting server...
[main] INFO ratpack.server.RatpackServer - Building registry...
[main] INFO ratpack.server.RatpackServer - Ratpack started for http://localhost:5050
[Heap policy parameters:
  YoungGenerationSize: 6710880
      MaximumHeapSize: 67108864
      MinimumHeapSize: 13421760
     AlignedChunkSize: 1048576
  LargeArrayThreshold: 131072]
[[1768 msec:  GC: before  epoch: 1  cause: CollectOnAllocation.Sometimes]
[1772 msec: Incremental GC (CollectOnAllocation.Sometimes) 20463K->17403K, 0.0040444 secs]
 [1772 msec:  GC: after   epoch: 1  cause: CollectOnAllocation.Sometimes  policy: by time: 50% in incremental collections  type: incremental
  collection time: 4044472 nanoSeconds]]
[[1845 msec:  GC: before  epoch: 2  cause: CollectOnAllocation.Sometimes]
[1850 msec: Full GC (CollectOnAllocation.Sometimes) 24543K->17403K, 0.0049823 secs]
 [1850 msec:  GC: after   epoch: 2  cause: CollectOnAllocation.Sometimes  policy: by time: 50% in incremental collections  type: complete
  collection time: 4982361 nanoSeconds]]

### [removed 200 lines for a better readability] ###

[[5479 msec:  GC: before  epoch: 53  cause: CollectOnAllocation.Sometimes]
[5483 msec: Full GC (CollectOnAllocation.Sometimes) 24543K->17403K, 0.0042101 secs]
 [5483 msec:  GC: after   epoch: 53  cause: CollectOnAllocation.Sometimes  policy: by time: 50% in incremental collections  type: complete
  collection time: 4210195 nanoSeconds]]
[[5549 msec:  GC: before  epoch: 54  cause: CollectOnAllocation.Sometimes]
[5551 msec: Incremental GC (CollectOnAllocation.Sometimes) 24543K->17403K, 0.0022523 secs]
 [5551 msec:  GC: after   epoch: 54  cause: CollectOnAllocation.Sometimes  policy: by time: 50% in incremental collections  type: incremental
  collection time: 2252302 nanoSeconds]]

And now let’s take a look at the memory consumption.

$ ps ef -o command,vsize,rss,%mem,size | grep ratpack | head -n 1
 \_ ./ratpack-graalvm-demo  281188 35812  0.2 62592

We could expect that. The application run with much smaller maximum heap size consumed eight times less memory - 35 MB in this case.

What is the right size?

It depends. You need to experiment with the optimal settings for your application. The good news is that you can compile the native image once and run tests with different settings without recompiling the image. I’ve run several tests with my demo Ratpack application, and I was able to limit max heap size to 32 MB. However, if I kept the default size of the even loop group (16 in my case), then I couldn’t get lower than 256 MB. Otherwise, the application pretty quickly started crashing with OutOfMemoryError.


1. https://github.com/JoeDog/siege
  • java
  • ratpack
  • graalvm
  • xmx

Groovy Cookbook

Spock random order of tests - how to?

  • April 6, 2019
  • 6 min. read
  • 0 Comments

Spock Framework executes test methods (features) in a single class (specification) in the declaration order. There is nothing wrong in this default behavior - we should write tests with their isolation in mind. However, in some cases, we would like to randomize test methods execution. Today we are going to learn how to do it.

Ratpack Cookbook

Ratpack on GraalVM - how to start?

  • February 15, 2019
  • 6 min. read
  • 0 Comments

The journey inside the exciting world of GraalVM continues. Today I would like to share with you...

Groovy Cookbook

GraalVM native image inside docker container - does it make sense?

  • January 19, 2019
  • 6 min. read
  • 0 Comments

We have learned how to create GraalVM native image from standalone Groovy script in the previous...

Learning Java

Installing GraalVM EE 1.0.0-RC14 with SDKMAN!

  • March 20, 2019
  • 6 min. read
  • 0 Comments

I love SDKMAN!. It made using multiple different Java distributions in a single operating system...

Any thoughts or ideas?

Let's talk in the comment's section 💬

Want to put a code sample in the comment? Read the Syntax highlighting guide for more information.
Empty
Latest blog posts
  • Merging JSON files recursively in the command-line
  • Jenkins Declarative Pipeline with the dynamic agent - how to configure it?
  • Groovy Ecosystem Usage Report (2020)
  • How to convert JSON to CSV from the command-line?
  • 5 Common Jenkins Pipeline Mistakes
  • How to merge two maps in Groovy?
  • Building stackoverflow-cli with Java 11, Micronaut, Picocli, and GraalVM
  • How to catch curl response in Jenkins Pipeline?
  • Atomic Habits - book review
  • Parsing JSON in command-line with jq: basic filters and functions (part 1)
Trending videos
Jenkins Declarative Pipeline vs Scripted Pipeline - 4 key differences | #jenkinspipeline

Jenkins Pipeline as a code is a new standard for defining continuous integration and delivery pipelines in Jenkins. The scrip...

5 Common Jenkins Pipeline Mistakes 🔥

In this Jenkins Pipeline tutorial video, I reveal five common Jenkins Pipeline mistakes and I explain how those mistakes can ...

Useful links
  • Start here
  • About
  • Archives
  • Resources
  • Privacy Policy
  • Merchandise
  • My Kit
  • RSS
  • Support the blog
Popular categories
  • Groovy Cookbook28
  • Jenkins Pipeline Cookbook9
  • Programmer's Bookshelf6
  • Micronaut Cookbook4
  • Ratpack Cookbook4
  • Learning Java4
  • jq cookbook3
  • How to3
  • Blog Reports2
Popular tags
affiliate async benchmark blogging book career cicd continuous-integration curl devops docker git github graalvm gradle grails groovy haskell hexo java java-8 jenkins jenkins-pipeline jenkinsfile jmh jq json junit learning maven metaprogramming micronaut native-image non-blocking progress ratpack reactive-programming reading recursion review rxjava sdkman session split spock stackoverflow string tail-call tail-recursion unit-test
  • Designed by @wololock
  • Created with Hexo
  • Hosted on GitHub
  • Deployed with Circle CI
  • License CC BY-NC-SA 4.0