Memory Leak in my Cinematics Based application

yes that’s what I thought at the beginning but no i’m sure I am not leaving references lying around… my code is straightforward.



I have a ConcurrentHashMap<Float, CinematicEvent> deleteEventsMap = new ConcurrentHashMap<Float, CinematicEvent>( );



where I put in it all the CinematicEvents that I want to remove. And later remove them in an AppState by making sure I use the removeEvent method u implemented (inside cinematics) to remove the event from the CinematicEventList as well as also removing it from the ConcurrentHashMap that I created.



Note that I did fork cinematics and replaced the CinematicEventsList with a Vector and TimeLine to a ConcurrentHashmap instead of hashmap - so I won’t have any threading issues. Not sure if that would cause any issues like that.

@garnaout said:
I am using default settings but tried ur approach and increased the direct memory size to 1024m but still the issue persists.


Then I guess it's time to use the profiler and find your leak.

alright did some profiling nad it related to the Float variable, it also related to some meshes class that I use to create meshes and assign them to a geometry so I get the object shape, but I just ruled that out by removing these classing (i’m basically removing everything to find the issue) and basically now the application is relatively simple:



I have many events of adding/removing geometries that go like this:



[java]if(eventType.equals(“add”))

{

Box box1 = new Box( Vector3f.ZERO, 1,1,1);

Geometry geom = new Geometry(“Box”, box1);

geom.setName(eventId;





Material mat1 = new Material(animationMode.getAssetManager(),

“Common/MatDefs/Misc/Unshaded.j3md”);

geom.setMaterial(mat1);



// add reservation to the cinematic scene

animationMode.insertObject(cinematic, triggerTime, geom);

}

// removeReservation

else

{

// remove reservation from scene

animationMode.removeObject(cinematic,triggerTime, geomName);

}[/java]



and basically the animationMode is an instance of a class that contains the CreateTrack that all it does is add the geometry to the scene code below:





in removeObject



[java] @Override

public void onPlay() {



// detach geom by name

animationMode.getAnimationNode().detachChildNamed(geomName);

}[/java]



in insertObject



[java] @Override

public void onPlay() {



animationMode.getAnimationNode().attachChild(geomName);

}[/java]







I simplified the code and still the memory leak persists… I don’t understand why…

@nehon are you sure the removeCinematicEvent(event) that you added does what it’s supposed to do? I just put a breakpoint on cinematic events and realized that the events that I am removing are staying in the ArrayList cinematicEvents

[java]

/**

  • removes the first occurence found of the given cinematicEvent.

    *
  • @param cinematicEvent the cinematicEvent to remove
  • @return true if the element has been removed

    */

    [/java]

    that’s pretty clear, despite the typo in “occurrence”
are you sure the removeCinematicEvent(event) that you added does what it’s supposed to do?


I meant if it might be the cause of a leak or something not being garbage collected. I'll investigate more.

Question, if I Want to remove events from cinematics buffer every certain time variable, that causes hiccups in animaion using that code that I am putting in an appstate called CinematicsCleaner:



[java]@Override

public void update( float tpf )

{

if(animationMode.cinematic.getTime() > safeTime) // safeTime originally 40 (my events duration are all < 10)

{

System.out.println(“Cinematics Cleaner activated”);



// Consume cinematics events list

for(int i=0; i < animationMode.cinematicsEvents.size(); i++)

{



if(!animationMode.cinematic.removeCinematicEvent( cinematicEvent ))

System.out.println(">>>>> SOMETHING IS WRONG!!!");



}



// update safeTime

safeTime += 10;



System.out.println(“Cinematic event size” + animationMode.cinematic.getCinematicEventsSize() );

System.out.println(“Our Map event size” +animationMode.getDeleteEventsMap().size() );



}



}[/java]





Although, System.out.println(">>>>> SOMETHING IS WRONG!!!"); is not called I get major hiccups in my animation whenever the cleaner is called. Any ideas?

well if you have plenty of events in the cinematic and that you are cleaning them by batch like that, no wonder why you have hiccups…



Also…looks like you’re basically removing the same event every time…



animationMode.cinematicsEvents looks like you’re holding a list of events yourself…that could be a good lead to find the place where you holds reference to the events causing your leak. Do you clear it sometime?

@nehon sorry I oversimplified my code for the sake of showing you the issue… I use the index and even by monitoring the size and LOTS of system outs, I am sure that I am deleting ALL the cinematic events - so thats not the issue (and in fact even with that I still have the memory leak so I am doubting at this point its the cinematicEvents).



I do have a list that I created myself that I use to safely delete the event after they’re completed, and yes I do clear that as well.



I was just interested if I would to do such an approach should I do it on a separate thread? I am assuming I shouldn’t do the batch of deletions on the rendering thread from the hiccups I saw.

Attaching is a snapshot of my profiling… I really could use some help on this one… as I have no idea how to investigate further. The long class keeps growing till I run out of memory. I do read events from a trace file and animate them. I did check for open input streams (I close them all). The geometries number in the scene does not grow (stable number of objects around 100 of them)



thanks in advance



attached are mmy profiler snapshots



http://i.imgur.com/6yMLU.png



http://imgur.com/kNnjL

Also I tried running that cleaner on a separate thread (so I don’t get those hiccups) but cineamtics doesn’t like it as I get the ConcurrencyModification error anytime I tried to delete cinematic events using the recent method that @nehon added





edit: @nehon where do you recommend calling that removeCinematicEvent() method if I have a lot of evnts to remove?



1- calling it from the rendering thread will cause hiccups



2- calling it from a separate thread will cause concurrency issues



3- what do u think of an approach to add something like OnFinish() in AbstractCinematicEvent class to consume the event automatically when it’s over?



edit: I stand corrected for no 3 that would be the same as onStop() - I thought that was for the whole cinematic… so u agree to call it there and consume the events as we go?

You have to remove them on the render thread. Just don’t do them all at once to avoid hiccups.

ok so if I consume them on OnStop() no problems happen as long as the speed of the cinematics is low. I crank that up and some error will happen.

@nehon if I create a new cinematic instance, should I worry about emptying the cinematicLists?

No if the cinematic is garbage collected and that you keep no reference to the events, all will be garbage collected…

so I did this test and when I click a button, without killing the main thread, I set cinematics to null and also the other thread I use to read the trace to null. The memory keeps growing… I am really confused now, I mean what’s left but the main (simpleApplication)???



I can’t get too much from profiling tried one that I attached snapshots above and another one that’s telling me that the long class is consuming the most. Not enough details…





Addition:



Also consuming the events from the track/channel directly causes some weird animations only when I pause then resume at cinematic speed > 1. Any idea why?

@nehon I added to cinematic class the folllowing code:



[java] /**

  • make sure cinematic is gc

    */

    @Override

    public void finalize() {

    System.out.println(“CINEMATIC CLASS IS GARBAGE COLLECTED!”);

    }[/java]



    when setting it to null it doesn’t trigger it, does that mean it’s not being gc? If so, that doesn’t make sense as I have only one instance of cinematic runnning all the time and I am setting that one to null - there can’t be any reference to it somewhere else.





    edit: also could you please explain to me why are we also removing cinematicEvent from keyframe? and why it’s there?



    the boolean of the remove method is false as the cinematicEvent does not successfully get removed from keyframe (only occasionally) but only from the Cinematic’s cinematicEvent.
@garnaout said:
Attaching is a snapshot of my profiling... I really could use some help on this one.. as I have no idea how to investigate further. The long class keeps growing till I run out of memory. I do read events from a trace file and animate them. I did check for open input streams (I close them all). The geometries number in the scene does not grow (stable number of objects around 100 of them)


AFAIK tell this looks like normal GC in a normal application running. Half of the max memory has been allocated. Just because the heap grows doesn't mean there is a leak. It only means that the JVM choose not to do a full GC because it doesn't think it is needed.
Now, if you run into out of memory exceptions that's an indication that something is holding references to objects. But then it would be very interesting to see what the OOME really says, is it direct buffers or heap memory that runs out?

when setting it to null it doesn’t trigger it, does that mean it’s not being gc? If so, that doesn’t make sense as I have only one instance of cinematic runnning all the time and I am setting that one to null – there can’t be any reference to it somewhere else.


If the finalizer doesn't run it probably means the object hasn't been GCd. But why should it? If nothing have references to it that only means that it is eligible for collecting, not that it actually will be collected when a GC runs. Basically you can't assume anything about what the GC does apart from that it really tries to keep the application from running out of memory.

As for the hiccups - idk, haven't used cinematics at all.
1 Like

I see what you’re saying… I am not running out of memory but the cinematicList (which is an ArrayList) is reaching like 300,000+ elements so I assumed that would be the reason (but I did reach 6gb consumption!)




If the finalizer doesn’t run it probably means the object hasn’t been GCd. But why should it? If nothing have references to it that only means that it is eligible for collecting, not that it actually will be collected when a GC runs. Basically you can’t assume anything about what the GC does apart from that it really tries to keep the application from running out of memory.

even if I set it to null and wait for quite some time?
@garnaout said:
cinematicList (which is an ArrayList) is reaching like 300,000+ elements so I assumed that would be the reason


If the list has 300,000 elements in it then 300,000 elements were added without being removed. GC has nothing to do with it.