Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (731)
Games in Android Showcase (217)
games submitted by our members
Games in WIP (799)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Object Pooling and arrays  (Read 2550 times)
0 Members and 1 Guest are viewing this topic.
Offline Deku

Junior Newbie


Exp: 4 years



« Posted 2017-02-08 03:03:56 »

I made a simple game for Android devices last month and learned first hand just how easy it is to use up the heap memory assigned to an app on Android and ended up with a functional game that calls the garbage collector far too often for my liking, resulting in annoying stutters about once per second.
To combat these memory issues I've been researching and implementing a generic object pool. It adds some abstract mess to my code, but its been super helpful in dealing with my memory niggles. I've run into a bit of an issue though and I've been failing to find information on this topic so I'd like to get some opinions here.

The object pools I've been coding have been working great for classes I've personally coded (Polygon, Vectors, game objects, etc.), but what about the memory allocations of external classes? Mainly I'm curious about how high performance Android games deal with the memory allocations of arrays and arraylists. If I create an arraylist of objects in a class that's run on each loop of the core game loop, I can easily reuse the memory of the objects this arraylist holds by handling their creation through an object pool and then recycling them into the pool once each object is no longer in use, but this leaves me with the memory overhead of the empty arraylist which was never recycled. What can I do with this? Create a separate object pool for the arraylist object to be recycled each frame?
Similarly, what can I do about a situation where I need to create some arrays holding primitives (lets say a float[] array) very frequently. Is there some means of clearing the memory of these arrays, in maybe another object pool? Maybe I just need pools everywhere...

If the question is unclear, I apologize. It's 3AM and I'm quite tired. Smiley
I'll check back tomorrow and can post sources of my current object pool implementation if the question seems unclear. I tried pooling arraylists but ended up creating my own memory leaks somehow, so I feel I'm not on the right track yet.
Offline h.pernpeintner

JGO Coder


Medals: 55



« Reply #1 - Posted 2017-02-08 08:25:42 »

I tackled this problem relatively successfully, my engine is finally allocation free. In the means of "allocation free at runtime". This should be the goal.

First of all, abandon all third party components that allocate too much memory. Pretty much all of the standard library can be used more or less garbage free. An exception is iteration over a hashmap and such things for example. But that means you should avoid creating collections at runtime. Using pools is one appraoch to tackle this problem. But for example you can decide that your scene is "memory static" once loaded. For example you could load all game objects, put them in a fixed size list once and done. On scene loading, colleciton is thrown away and a new scene creates its own...which should be fine.

If you have requirements that prevents you from using this approach, we should discuss your case more particularly.

For your "per frame primitive collections" I would go for the same appraoch: Add a "cache" to your scene class (list, intlist, whatever) and have it the size you need for this scene. Don't free it up ever. Throw it away when you want to change scene automatically, as it is created together with the scene.

Does that make sense? A multithreaded renderer appraoch has different needs though. Give us a hint if you have such an environment.
Offline princec

« JGO Spiffy Duke »


Medals: 906
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #2 - Posted 2017-02-08 09:32:13 »

Grrr to Android for still having a hopeless garbage collector.

Pooling is effective and works nicely but especially for large, complex, or expensive to construct objects - arrays and arraylists are good candidates. Use Arrays.fill to clear them out when they are needed.

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Deku

Junior Newbie


Exp: 4 years



« Reply #3 - Posted 2017-02-08 19:50:47 »

Thanks guys. The advice alone already put me in the right direction.

I saw first hand the issue with using iterators to parse through hashmaps (or arrays via iterator style for loops) and I've had to change a bunch of looping logic to reduce memory usage.
To tackle the the pooling of arrays I extended my object pool class and implemented a pool that creates arrays of fixed sizes using the component type of the class passed into the pool as a generic.
I'm hoping to reach some sort of memory static scene when complete but my engine was never prepared for this overall structure so its slow progress. Learning as I go! Smiley

Once I get the lower-level engine code Android-optimized it should be fairly straight forward to work on a static scene that loads objects once and reusing them within the world from thereon.
Offline Catharsis

JGO Ninja


Medals: 68
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #4 - Posted 2017-02-08 21:18:02 »

Indeed it's a problem on Android. I was very lucky to have tackled this area long before starting Android development in '08 on the desktop previously and refined things even further with my TyphonRT efforts especially after switching to a component architecture which is based on HashMaps. I created a custom collections implementation which recycles iterators automatically at the end of iteration in loops in addition to internal objects used in all the collections. Even better is that the component architecture allows easy recycling of components (objects!). So yeah you'll get hit hard on Android using iterators and the standard collection API for anything near real time usage. Even worse was the piss poor annotation support as it lacked all caching and did a bunch of string comparisons (left over poor implementation from Harmony), so I have my own annotation cache for TyphonRT. I had a demo showing milliseconds for my cache and up to 10 seconds for the same amount of queries by the Android API in a tight loop. In addition I found early in ~'12 though never reported a serious flaw in Enums on Android. At that point I just gave up on reporting things as Google simply didn't care about quality or performance to the degree that I thought it was important and worked around it as the workarounds work on any version of Android. Some details on the Enum bug here.

As you noted though that recycling variable length primitive arrays is troublesome in general. That is worked around for say in a component architecture you have a ParticleData component with primitive arrays for tracking X particles. You recycle this object / component and when you pull it off the pool you know the primitive arrays are the right length, etc. So recycling objects with explicit primitive array lengths is fine.

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline princec

« JGO Spiffy Duke »


Medals: 906
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #5 - Posted 2017-02-08 23:04:05 »

Hmm I don't really agree with you on the enum flaw... the implementation is valid. It sounds to me like you were rather just hoping to use hashCode() instead of equals() for identity comparisons and while it appeared to work on the desktop, it fell over on Android...

Cas Smiley

Offline Catharsis

JGO Ninja


Medals: 68
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #6 - Posted 2017-02-08 23:30:05 »

How is it valid? It differs from the JDK implementation which is the identity hashcode. It's clearly a mistake in the Harmony implementation never corrected in Android. Even Romain Guy in the discussion went, "oh shit..." or thereabout.. Go look at the JDK source and compare against Android. HashMaps will fail on Android if you have two separate enums with the same name at the same ordinal. QED.

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline KaiHH

JGO Kernel


Medals: 416



« Reply #7 - Posted 2017-02-08 23:31:14 »

That implementation of hashCode() is indeed completely valid according to the well known "equals/hashCode contract".
Read especially the first sentence of the third rule:
Quote
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results.
Offline Catharsis

JGO Ninja


Medals: 68
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #8 - Posted 2017-02-08 23:45:01 »

You guys are nitpicking. It's an extremely poor implementation of hashCode valid or not... Which causes instant clashes with HashMap. You have to use IdentityHashMap when using enums as keys on Android.

JDK:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Enum.java?av=f#151

Harmony / same code as in Android for 8 years until switch to OpenJDK:
https://github.com/apache/harmony/blob/java6/classlib/modules/luni/src/main/java/java/lang/Enum.java#L102

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Offline princec

« JGO Spiffy Duke »


Medals: 906
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #9 - Posted 2017-02-08 23:45:57 »

@KaiHH Exactly. HashMap does not use hashCode() to determine key equality - it uses the hashCode() to bucket keys. After it has found the right bucket, it then scans a list of keys using equals() to find a match.

@Catharsis No, I think you'd be wrong there. HashMap works whether hashCode() is implemented that way or not provided hashCode() keeps the contract as specified, which it does for both implementations.

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Catharsis

JGO Ninja


Medals: 68
Projects: 1
Exp: 21 years


TyphonRT rocks!


« Reply #10 - Posted 2017-02-09 02:10:05 »

Unfortunately it's not something I can confirm right away as it's been a while since I've been doing Android dev and my larger TyphonRT projects (video engine) are stuck back at a gradle version well below the current setup I'm running. IE I don't want to spend the ~3+ hours now to get things running to verify this point; updating gradle from an old version and a multi-module IDE project is no fun... 

It was a bit more nuanced and problems only occurred when running a large project based on TyphonRT when using HashMap as the component storage versus IdentityHashMap. The problem occurred when mixing 'Class / .class' and enum types as keys in the same HashMap and not just various enums as keys. When i get back to Android dev after my Javascript adventures / server side stuff is complete later this year I'll do the test and report back if I remember though this thread might be locked by then.  If I recall though it was because Class and Enum have different hashCode implementations; I could be wrong. Pending verification....

Check out the TyphonRT Video Suite:
http://www.typhonvideo.com/

Founder & Principal Architect; TyphonRT, Inc.
http://www.typhonrt.org/
http://www.egrsoftware.com/
https://plus.google.com/u/0/+MichaelLeahy/
Pages: [1]
  ignore  |  Print  
 
 

 
Archive (337 views)
2017-04-27 17:45:51

buddyBro (536 views)
2017-04-05 03:38:00

CopyableCougar4 (979 views)
2017-03-24 15:39:42

theagentd (1016 views)
2017-03-24 15:32:08

Rule (994 views)
2017-03-19 12:43:22

Rule (976 views)
2017-03-19 12:42:17

Rule (974 views)
2017-03-19 12:36:21

theagentd (1073 views)
2017-03-16 05:07:07

theagentd (993 views)
2017-03-15 22:37:06

theagentd (762 views)
2017-03-15 22:32:18
List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05

SF/X Libraries
by SkyAphid
2017-03-02 06:38:56

SF/X Libraries
by SkyAphid
2017-03-02 06:38:32

SF/X Libraries
by SkyAphid
2017-03-02 06:38:05

SF/X Libraries
by SkyAphid
2017-03-02 06:37:51
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!