- Home /
Optimization on list handling
I need to keep a very large list (> 10,000 members) of a custom type in memory. Also I have to do some operations that currently create other list during their scope which in some cases are longer than a function call (such as a filter of the main list). I am having some memory issues on the iPad.
These other lists are also of the same custom type (currently). Would it make any difference (memory wise) if I use a list of integers with just the indexes of the main list instead of a parallel lists of that type?
Also, changing this type from a class to a struct would do any good?
Any other suggestions/advices on handling large sized lists are welcome!
Answer by Languard · Oct 26, 2011 at 02:14 PM
For a mobile device, I would ask 'Do you really need those 10k items in memory at all times?' Assuming each item holds 10MB of data, that's 100MB you're burning just for that list. I believe first-gen iPads have 256MB of memory which you have to share with the OS and all other apps running. Oh and your models, and your graphics, and your sounds...you get the picture. Even if the size isn't an issue, say each item is 500KB, I'd still be hesitant to have a list of 10k items on a mobile app unless it is truly necessary.
Regarding the parallel list question, it depends on how you have it setup. Take this C# example:
List<Object> listA = new List()<Object>;
List<Object> listB = new List()<Object>;
Object a = new Object();
listA.Add(a);
listB.Add(b);
There is a small memory overhead, but both lists are pointing to the same location in memory so it's rather minor. However if you do this:
List<Object> listA = new List()<Object>;
List<Object> listB = new List()<Object>;
Object a = new Object();
listA.Add(a);
a = new Object();
listB.Add(b);
Then you're using 2x the memory because you have multiple copies of the object.
For managing that many items on a mobile app, my first approach would be to identify the truly core items, the ones that must be available instantly at all times. I would then load those into a static list. Then I would create groups of lists based on where I am in the game, and dynamically load those as needed. No need to have the shop keeper's inventory loaded if I'm down in the dungeon and can't shop.
Class to struct? Shouldn't have any impact from a memory perspective. I would actually recommend against this as in C# structs are passed by value instead of by reference, which in a mobile app could be a major problem.
Hope this helps.
Answer by Owen-Reynolds · Oct 26, 2011 at 02:28 PM
Some rough envelope calulations: suppose your custom type is 3 ints and a float. That's about 16 bytes, so 160,000 bytes ~0.16M for a size 10,000 array. Yes, structs use less memory. A struct is part of the array. A class is created where-ever, and the actual array has a 4-byte pointer to each item -- goes to ~0.2M total space. The larger the custom class is, the less you notice the extra 4 bytes.
If you use a linked list, you have to pay for a pair (I believe) of extra 4-byte previous/next pointers: a linked list costs you per item: 16 + 4*2(next/prev) + 4(pointer to item) = 28. Almost double the space for an array, but, again, the extra 12ish bytes don't matter as much as your custom datatype gets bigger. Of course, if you do a lot of mid insert/delete, you pretty much need the linkedList for speed.
"...a list of integers with just the indexes of the main list?"
Yes. The absolute most memory efficient way to create a sublist would be to create an array of ushorts
as indexes. An unsigned short is only 2 bytes and counts 0 to 65,000. If you used structs for the main type, you pretty much need to store indexes. If the custom datatype is a class, the automatic reference to it costs you only 4 bytes anyway, and might be easier to use. But, if you can't put an upper bound on the sublist size, the arrays need to be size 10K.
Say you have 6 sublists and preallocate a size 10K array for each. That's 6arrays 10K 2bytes= 0.12M for all sublists. Say the sublists tend to be about 2000 long and you used linked lists. That's 6lists 2Klong 12bytesSize = 0.144M. About the same either way, and about doubles the total space you need. As your custom data type gets larger (12 ints and a string,) the size of the sublists is a smaller and smaller proportion and it isn't worth getting cute to save space on them.
The best improvements are then in the custom data type -- tricks like using uchar
for ints you know only go from 0 to 255; or storing 12.39 as 1239 in a 2-byte short, if you know you only need 2-digits precision and never go above 320.00.
Do you guys know if that used/allocated heap sizes showed in the profiler are the true total memory spent by the app? Because I am getting low memory warnings and my used/allocated sizes are 18$$anonymous$$B / 25 $$anonymous$$B even with few or none other apps running...
This app I am working on has no models, it´s a 100% GUI app. That 10$$anonymous$$ itens list is needed for a scrollview. I could load the itens on demand but I am avoiding this aproach because of reasons not relevant to this question topic.
The custom type is all composed of strings (which I guess are even worse than the examples pointed).
One more thing! What could cause an app to run ok on a certain iPad and crash all the time in another one with absolutely the same specs (iOS, generation...etc)?
1) I found out that the problem was unrelated to the list´s size... it was a texture problem! If anyone ever read this comment, be cautious with high resolution textures configured as "GUI", they freaking eat out all your memory. A group of them end up causing low memory warnings and crashing your app...
2) The app crashing was partially related to the low memory warnings and a malfunctional iPad.
Your answer
Follow this Question
Related Questions
A node in a childnode? 1 Answer
UI-based game memory and performance issue. 1 Answer
Sprite-based animation - mobile memory issue 0 Answers