Imagine you are using JMeter to test an application that is going to return a large volume of data, in response to every request – a reporting application, for example. Your goal is to test the performance of the system in an end of the month scenario, where a large number of users (say 1000) are expected to login to the application and download huge (say 100MB) reports, during the peak hour.
Can your load generator handle such a huge response? Will it scale up to 1000 users under these conditions?
I tried to test one such application (with Jmeter) and guess what! My load generator ran out of heap space at extremely low loads (~20 users). That means, to test with 1000 users I would need 50 LOAD GENERATORS?!! That’s insane!
There’s got to be a better way to do this!
To identify the solution, we need to understand the problem first. To understand why the JVM runs out of heap memory, I decided to take a look at what’s in the heap. This is what I found.
99.5% of all the heap space is being consumed by only 2.8% of the objects. And if you look deeper, you can see that it is a byte array that consumes all this space. I guess, you can already see where this is going.
I tried to dig in further, to see which all objects reference this byte array. As can be seen in the below screenshot, there are no references to this from any other object.
So, there is a large byte array in memory and is not referenced by anything else. So, what could be in it?!
I can think of only one – the response to request made!
I know that, as long as you don’t try to parse the response, Loadrunner discards response data by default. That reduces the memory footprint of the virtual user threads. But, JMeter does not seem to be doing this by default. The default behaviour with JMeter is to store the response in the sample result.
To change this behaviour, you need to check the option “Save response as MD5 hash” in the HTTP Request Sampler. If you enable this option, then the response is not stored in the sample result. Instead, the 32 character MD5 hash of the data is calculated and stored. That reduces the overall memory footprint of each of the virtual user threads.
To test if this works for my test, I enabled this option and repeated the test.
Voila!! My load generator could generate 1000 users without breaking a sweat. The memory footprint went down by ~ 18 times.
Fig 4. Heap usage with the default settings
Hope this helped!