I am using spring boot with JPA Hibernate. I am monitoring the service for Heap and found that each of my request is taking around 40-50 MB.
So the memory gets increased, after few requests GC runs, it frees the memory and this goes on forever.
So my first question is that is this memory leak?
Also I am trying to find what is causing this. So, I have used Runtime.getRuntime() freeMemory and totalMemory() to identify that around 15MB is getting used when getting one db call and populating projection with it
public interface RecommendationProjection {
public String getType();
public boolean getIsOK();
public int getId();
public int getTagCount();
public double getQuality() ;
public LocalDateTime getLastActivity();
}
and hibernate returns 567 records, so basically what I am getting from DB is list of 567 above projection, But what i dont understand that how could this object take such high memory? Is hibernate causing this?
When using projection, hibernate queries for specific field or fetches all fields from database?
Then I am mapping this domain to DTO, which again uses 15-20MB memory? this is my DTO
public class RecommendationInfoDTO {
private String type;
private boolean isOK;
private int id;
private int tagCount;
private double quality ;
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss", timezone="IST")
private LocalDateTime lastActivity;
.. getters and setters
}
FYI : For monitoring I am using VisualVM. Can anybody tell me what is possible issue?
I have also analyzed heap dump but could not get anything?
This is my heap dump diff.
I am firing 6 hibernate queries in a request and 3 simple plain mysql queries(using jdbc call)
Issue is just 1 hibernate call. I think some thing is wrong with my hibernate ? Is there any way I could do request based profiling?
Gc / Memory Graph
Heap dump sorted on size
This looks to me to be normal behavior.
So my first question is that is this memory leak?
No. Memory leaks require for the memory to remain allocated beyond its useful life. Since your GC is clearing the total memory space consumed by the query, you are not leaking, you're simply using memory.
But what i dont understand that how could this object take such high memory?
The object isn't taking much memory, it's the 567 instances of the object per query that are taking the memory.
Lets take a look to explain why:
Each instance of your projection contains
String
of unknown length (Strings are not primitives, so there are a significant number of metadata attributes one top of the pure character count, but lets just say 1 byte)boolean
which allocates 1 byteint
of a byte eachdouble
of 2 bytesLocalDateTime
which is made of several fields (so lets be optimistic and say at 2 bytes)So each instance is at least 8 bytes. 567 * 8 = 4536 bytes minimum per query.
You're firing 6 queries against this dataset 4536 * 6 = 27216 bytes per method call
Some of this is overhead in hibernate which gets reused between calls, so you won't quite see the full theoretical footprint.
This is relatively close to what you're observing, so I don't think anything is misbehaving.
If you're expecting a smaller footprint, reevaluate your approach to reuse as much data as possible to reduce the number of queries you have to make.
Below is my view:
So the memory gets increased, after few requests GC runs, it frees the memory and this goes on forever.
So my first question is that is this memory leak?
Not necessarily a memory leak. But you need to run and hit the application for a longer period of time and see how the memory is getting released during GC cycles. As long as the memory usage kind of follows a sawtooth pattern it is a one indicator that the GC is able to reclaim the garbage and memory is utilized efficiently.
When using projection, hibernate queries for specific field or fetches all fields from database?
No it fetches only the specified columns in case of projection.
Then I am mapping this domain to DTO, which again uses 15-20MB memory?
It is not only your DTOs, but hibernate
and on top of spring-data-jpa
would be creating their own objects internally to fulfill the query and those objects might be awaiting GC. As long as they are getting reclaimed after GC cycle and the memory usage is not increasing constantly after each GC, it is a healthy sign.
But more than the memory used by each request, you may want to look at the bigger picture and some of the items (not an exhaustive/complete list) could be:
And finally you may want to go through java8 GC tuning guide to understand the GC and tuning it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With