Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate associations using too much memory

I have a table "class" which is linked to tables "student" and "teachers". A "class" is linked to multiple students and teachers via foriegn key relationship.

When I use hibernate associations and fetch large number of entities(tried for 5000) i am seeing that it is taking 4 times more memory than if i just use foreign key place holders. Is there something wrong in hibernate association?

Can i use any memory profiler to figure out what's using too much memory?

This is how the schema is:

class(id,className) 

student(id,studentName,class_id)
teacher(id,teacherName,class_id)

class_id is foreign key..

Case #1 - Hibernate Associations

1)in Class Entity , mapped students and teachers as :

@Entity
@Table(name="class")
public class Class {

private Integer id;
private String className;

private Set<Student> students = new HashSet<Student>();
private Set<Teacher> teachers = new HashSet<Teacher>();

@OneToMany(fetch = FetchType.EAGER, mappedBy = "classRef")
@Cascade({ CascadeType.ALL })
@Fetch(FetchMode.SELECT)
@BatchSize(size=500)
public Set<Student> getStudents() {
    return students;
}

2)in students and teachers , mapped class as:

@Entity
@Table(name="student")
public class Student {

private Integer id;
private String studentName;
private Class classRef;

@ManyToOne
@JoinColumn(name = "class_id")
public Class getClassRef() {
    return classRef;
}

Query used :

sessionFactory.openSession().createQuery("from Class where id<5000");

This however was taking a Huge amount of memory.

Case #2- Remove associations and fetch seperately

1)No Mapping in class entity

@Entity
@Table(name="class")
public class Class {

private Integer id;
private String className;

2)Only a placeholder for Foreign key in student, teachers

@Entity
@Table(name="student")
public class Student {

private Integer id;
private String studentName;
private Integer class_id;

Queries used :

sessionFactory.openSession().createQuery("from Class where id<5000");
sessionFactory.openSession().createQuery("from Student where class_id = :classId");
sessionFactory.openSession().createQuery("from Teacher where class_id = :classId");

Note - Shown only imp. part of the code. I am measuring memory usage of the fetched entities via JAMM library.

I also tried marking the query as readOnly in case #1 as below, which does not improve memory usage very much ; just a very little. So that's not the solve.

    Query query = sessionFactory.openSession().
            createQuery("from Class where id<5000");

    query.setReadOnly(true);
    List<Class> classList = query.list();
    sessionFactory.getCurrentSession().close();

Below are the heapdump snapshots sorted by sizes. Looks like the Entity maintained by hibernate is creating the problem..

Snapshot of Heapdump for hibernate associations program Snapshot of Heapdump for hibernate associations program

Snapshot of heapdump for fetching using separate entities Snapshot of heapdump for fetching using separate entities

like image 810
nikel Avatar asked Feb 10 '16 19:02

nikel


1 Answers

You are doing a EAGER fetch with the below annotation. This will in turn fetch all the students without even you accessing the getStudents(). Make it lazy and it will fetch only when needed.

From

@OneToMany(fetch = FetchType.EAGER, mappedBy = "classRef")

To

   @OneToMany(fetch = FetchType.LAZY, mappedBy = "classRef")
like image 157
Ashraff Ali Wahab Avatar answered Oct 04 '22 04:10

Ashraff Ali Wahab