Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java request taking 40-50MB memory(Spring JPA Hibernate)

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?

enter image description here

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

enter image description here

Heap dump sorted on size

enter image description here

like image 583
Ankit Bansal Avatar asked Mar 30 '18 12:03

Ankit Bansal


2 Answers

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

  • a 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)
  • a boolean which allocates 1 byte
  • 2 int of a byte each
  • a double of 2 bytes
  • and LocalDateTime 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.

like image 137
Stephan Avatar answered Nov 13 '22 23:11

Stephan


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:

  1. See how the memory usage is over a period of time for the normal load and peak load scenarios.
  2. How frequently are minor and major GC happening and how it impacting the application?
  3. Is the application spending too much of time in GC itself"?
  4. Tune the GC based on the application behavior. For ex: is the app creating too many short lived objects for serving requests etc.
  5. Given the heap/GC configuration, is the application able to meet your application response time and throughput as expected?

And finally you may want to go through java8 GC tuning guide to understand the GC and tuning it.

like image 40
Madhusudana Reddy Sunnapu Avatar answered Nov 13 '22 22:11

Madhusudana Reddy Sunnapu