Are JPA Courts that are not in use collecting trash and why?

Building a Spring Application that pulls data from the Internet using API I stuffed multiple times in OutOfMemoryError: GC overhead limit exceeded

. After some profiling sessions, I started to question my model, which looks something like this:

@Entity
class A {
  @Id
  private Integer id;
  private String name;

  @OneToMany
  private Set<B> b1;

  @OneToMany
  private Set<B> b2;
}

@Entity
Class B {
  @Id
  private Integer id;

  @ManyToOne
  private A a1;

  @ManyToOne
  private A a2;
}

      

There is a CrudRepository assigned to manage these entities (JPA + EclipseLink). Default object loading, which in this case means impatient AFAIK.

The program tries to do the following:

// populates the set with 2500 A instances.
Set<A> aCollection = fetchAFromWebAPI();
for (A a : aCollection) {
  // populates b1 and b2 of each A with a 100 of B instances
  fetchBFromWebAPI(a);
  aRepository.save(a);
}

      

By the end of this process, there will be 500 instances of B, except that it never reaches the end due OutOfMemoryError: GC overhead limit exceeded

. Now I could add more memory, but I want to understand why all these instances are not garbage collected? Save A in the database and forget about it. This is because instances of instances of B have their own b1 or b2, which in turn refer to instances of A

Another observation I made is that the process runs significantly smoothly the first time there is no data in the database.

Is there something fundamentally wrong with this model or with this process?

+3


source to share


2 answers


A JPA transaction has an associated session cache of all the entities used in the transaction. By keeping your entities, you keep injecting more instances into this session. In your case, I would recommend using a EntityManager.clear()

per object n

that decouples persistent objects from the session and makes them available for garbage collection.

If you want to know more about the lifecycle of JPA objects, you can refer for example to



http://www.objectdb.com/java/jpa/persistence/managed

Edit: Also, BatScream's answer is also correct: you seem to be accumulating more and more data in each iteration that the set is still referenced by. You might want to consider removing the instances that you have processed from the set.

+3


source


The collection aCollection

continues to grow after each iteration. Each instance A

will be populated with 200 instance elements B

after each loop. Hence your heap space is eaten up.

All instances A

in the collection are aCollection

always available when the garbage collector is running during this period, since you are not deleting the one you just saved A

from the collection.



To avoid this, you can use Set Iterator

to safely remove the newly processed instance A

from the collection.

+2


source







All Articles