So I am part way through writing my first game on Android and after watching a lengthy presentation on optimising for games, I have been checking my allocations. I have managed to get rid of all in-game allocations apart from ones made my ArrayList when it creates an implicit iterator for the for(Object o : m_arrayList) convention.
There are a fair few of these iterations/allocations since all of my game objects, ai entities etc. are stored in these for their ease of use.
So what are my options?
I could, theoretically specify sensible upperbounds and use arrays, but I like the features of ArrayList such as exists and remove that keep code clean and simple.
Override ArrayList and provide my own implementation of iterator() that returns a class member rather than allocating a new iterator type each time it is used.
I would prefer to go for option 2 for ease of use, but I had a little go at this and ran into problems. Does anyone have an example of what I described in option 2 above? I was having problems inheriting from a generic class, type clashes apparently.
The second question to this then is are there any other options for avoiding these allocations?
And I guess as a bonus question, Does anyone know if ArrayList preallocates a number of memory slots for a certain amount (specified either in the ctor or as some shiftable value) and would never need to do any other allocations so long as you stay within those bounds? Even after a clear()?
Thanks in advance, sorry there is so much there but I think this information could be useful to a lot of people.
Use positional iteration.
for ( int i = 0, n = arrayList.size( ); i < n; ++i )
{
Object val = arrayList.get( i );
}
That's how it was done before Java 5.
For preallocation.
ArrayList arrayList = new ArrayList( numSlots );
or at runtime
arrayList.ensureCapacity( numSlots );
And for a bonus -> http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html
I'll answer the bonus question first: Yes, ArrayList does pre-allocate slots. It has a constructor that takes the desired number of slots as an argument, e.g. new ArrayList<Whatever>(1000). clear does not deallocate any slots.
Returning a shared iterator reference has a few problems. The main problem is that you have no way of knowing when the iterator should be reset to the first element. Consider the following code:
CustomArrayList<Whatever> list = ...
for (Whatever item : list) {
doSomething();
}
for (Whatever item : list) {
doSomethingElse();
}
The CustomArrayList class has no way of knowing that its shared iterator should be reset between the two loops. If you just reset it on every call to iterator(), then you'll have a problem here:
for (Whatever first : list) {
for (Whatever second : list) {
...
}
}
In this case you do not want to reset the iterator between calls.
#Alexander Progrebnyak's answer is probably the best way to iterate over a list without using an Iterator; just make sure you have fast random access (i.e. don't ever use a LinkedList).
I'd also like to point out that you are getting into some pretty heavy micro-optimization here. I'd suggest that you profile your code and find out if allocating iterators is a genuine problem before you invest much time in it. Even in games you should only optimize what needs optimizing, otherwise you can spend many, many days shaving a few milliseconds off a minute-long operation.
Related
Object A has method B(), and lives for most of the life of the application. B calls object C method D(). D() returns an array holding up to x MyData objects. MyData might be a POD (plain old data)/PDS (passive data structure) or might be more, but a MyData can be reused by calling methods or setting fields; its identity or functionality isn't cast in stone during construction or otherwise.
Currently B() is defined like:
class A {
public B() {
MyData[] amydata = c.D( 5 );
:
:
}
}
Currently D() is defined like:
MyData[] D( int iRows ) {
MyData[] amydata = new MyData[ iRows ];
for ( int i = 0; i < iRows; i++ ) {
if ( no more data )
return amydata;
amydata [ i ] = new MyData();
// calculate or fill in MyData structure.
}
return amydata;
}
A is going to be always, or for a long time (e.g., until the user reconfigures it) be asking for the same number of rows, even though the data will differ.
So what if I have the caller pass in the array reference:
class A {
int iRequestSize = 5;
int iResultSize;
MyData[] amydata = new MyData[ iRequestSize ];
public B() {
iResultSize = c.D( iRequestSize, amydata );
:
:
// use up to iResultSize even though array is potentially bigger.
}
}
// returns number of rows actually used
int D( int iRowsMax, MyData[] amydata ) {
for ( int i = 0; i < iRowsMax; i++ ) {
if ( no more data )
return i;
if ( amydata [ i ] == null )
amydata [ i ] = new MyData();
// calculate or fill in MyData structure.
}
return iRowsMax;
}
I'm a C++ guy and new to Java, but it seems that assuming MyData can be recycled like this, the second version should avoid creating and copying MyData's, as well as eliminating garbage collection?
I would say the second variant is worse.
In the first variant amydata and all the objects referenced by it can be garbage collected as soon as the method B() exits (assuming that B doesn't store a reference to amydata somewhere else.)
In the second variant amydata cannot be garbage collected as long as the instance of A lives.
Consider the case where upon the first call to D() it returns 5 references to MyData objects, but on subsequent calls it returns no more rows. In the first variant the amydata array and the 5 referenced MyData objects can be garbage collected as soon as B() returns. But in the second variant neither the amydata array nor the 5 MyData objects referenced through it can be garbage collected - possibly never during the whole runtime of your application.
Remember: the Java Garbage Collector is optimized for many short-lived objects
Disclaimer: Reading the OP's comments, I have to admit that I didn't get his real intent, i.e. to develop a soft-real-time application, avoiding garbage collection as much as possible, a very special and rare situation in the Java world.
So the following answer does not match his problem. But as a casual reader migrating from C++ to Java might stumble over this question and answer, he/she might get some useful hints on typical Java programming style.
Although the syntax of Java and C++ have quite some similarities, because of the very different runtime environments, you should adopt a different coding style.
As a decades-long Java guy, I'd surely prefer the original method signature. As a caller of the D() method, why should I create the results data structure instead of getting it from the method I am calling? That reverses the natural flow of data.
I know, in good old C times when dynamic memory management meant lots of headache, it was very common to prepare the result array outside of the function and have the function only fill in the results, the way you wrote the second version. But forget about that with Java, and just let the garbage collector do its job (and it's very good at that job). Typically trying to "help" the GC results in code that's in fact less efficient and harder to read. And if you really want to stick to that style, there's no need to pass both the max rows number and the array, as the array itself knows its length (that's different from old-style C arrays), giving the max row number.
You assume
the second version should avoid creating and copying MyData's
That sounds like a misconception about Java's inner workings. Every time you execute a new MyData(...) expression, you create a new instance somewhere on the heap. Providing a MyData[] array doesn't avoid that. Translated to C terminology, the array just holds pointers to MyData objects, not the real objects. And Java instances are hardly ever copied (unless you explicitly call something like object.clone()). It's just the reference (= pointer) to the instance that gets copied when you assign something to a variable.
But even the first version is far from perfect, if I understand its purpose correctly. The D() method itself can determine when there's no more data available, so why should it return an array longer than necessary? With Java arrays that's a bit inconvenient, so typical Java code returns a List<MyData> in similar situations.
One more comment on the MyData() constructor and later "calculate or fill in MyData structure". I know that style exists (and is quite popular in the C family of languages), but it's not predominant in Java, and I especially dislike it. To me, it sounds like asking "Give me a car" and getting just a skeleton instead of a usable car. If I want it to have wheels, an engine and seats, I later have to supply them myself. If a usable car needs the selection of options, I want to supply them when ordering the car / calling the constructor, so that I can honestly call the result a car instead of a skeleton.
And finally a comment on the Java naming conventions: the vast majority of Java code follows the conventions, so your method names beginning with upper case look very strange to me.
I am writing a game engine, in which a set of objects held in a ArrayList are iterated over using a for loop. Obviously, efficiency is rather important, and so I was wondering about the efficiency of the loop.
for (String extension : assetLoader.getSupportedExtensions()) {
// do stuff with the extension here
}
Where getSupportedExtension() returns an ArrayList of Strings. What I'm wondering is if the method is called every time the loop iterates over a new extension. If so, would it be more efficient to do something like:
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (String extension : supportedExtensions) {
// stuff
}
? Thanks in advance.
By specification, the idiom
for (String extension : assetLoader.getSupportedExtensions()) {
...
}
expands into
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();)
{
String extension = it.next();
...
}
Therefore the call you ask about occurs only once, at loop init time. It is the iterator object whose methods are being called repeatedly.
However, if you are honestly interested about the performance of your application, then you should make sure you're focusing on the big wins and not small potatoes like this. It is almost impossible to make a getter call stand out as a bottleneck in any piece of code. This goes double for applications running on HotSpot, which will inline that getter call and turn it into a direct field access.
No, the method assetLoader.getSupportedExtensions() is called only once before the first iteration of the loop, and is used to create an Iterator<String> used by the enhanced for loop.
The two snippets will have the same performance.
Direct cost.
Since, as people said before, the following
for (String extension : assetLoader.getSupportedExtensions()) {
//stuff
}
transforms into
for (Iterator<String> it = assetLoader.getSupportedExtensions().iterator(); it.hasNext();) {
String extension = it.next();
//stuf
}
getSupportedExtensions() is called once and both of your code snippets have the same performance cost, but not the best performance possible to go through the List, because of...
Indirect cost
Which is the cost of instantiation and utilization of new short-living object + cost of method next(). Method iterator() prepares an instance of Iterator. So, it is need to spend time to instantiate the object and then (when that object becomes unreachable) to GC it. The total indirect cost isn't so much (about 10 instructions to allocate memory for new object + a few instructions of constructor + about 5 lines of ArrayList.Itr.next() + removing of the object from Eden on minor GC), but I personally prefer indexing (or even plain arrays):
ArrayList<String> supportedExtensions = ((IAssetLoader<?>) loader).getSupportedExtensions();
for (int i = 0; i < supportedExtensions.size(); i++) {
String extension = supportedExtensions.get(i);
// stuff
}
over iterating when I have to iterate through the list frequently in the main path of my application. Some other examples of standard java code with hidden cost are some String methods (substring(), trim() etc.), NIO Selectors, boxing/unboxing of primitives to store them in Collections etc.
In the two styles below, an Iterator object is allocated. Is it useful to check if the collection is empty before iterating? I don't know if this qualifies as "premature optimization". Hopefully, someone with deep knowledge of JVM garbage collectors can provide insight.
Also, I don't know how the Java compiler handles for-each loops. I assume style B is converted to style A automatically. But... maybe an empty check is included.
Loop Style A
Collection<String> collection = ...
Iterator<String> iter = collection.iterator();
while (iter.hasNext()) {
String value = iter.next();
// do stuff
// maybe call iter.remove()
}
Loop Style B
Collection<String> collection = ...
for (String value : collection) {
// do stuff
}
Loop Style A (Modified)
Collection<String> collection = ...
if (!collection.isEmpty()) {
Iterator<String> iter = collection.iterator();
while (iter.hasNext()) {
String value = iter.next();
// do stuff
// maybe call iter.remove()
}
}
Loop Style B (Modified)
Collection<String> collection = ...
if (!collection.isEmpty()) {
for (String value : collection) {
// do stuff
}
}
Yes, this is pretty definitely going to be a premature optimization, if it can ever help. Your loop would have to be extremely performance critical, and usually called with empty collections, and for some reason unable to optimize away most of the cost of creating an actual iterator object.
In that perfect storm, this massive source ugliness could possibly be justified. But more likely you could rearrange something to help the compiler optimize better, like keeping your iterator local.
The iterator object is (usually?) function-local and therefore cheap to create (could just live in registers, no heap allocation needed). See https://www.beyondjava.net/escape-analysis-java for some details about how JVMs do "scalar replacement" on an Object if escape analysis proves that it's purely local, no references to it are visible to other code. So the possible savings don't even include a memory allocation.
If this did JIT-compile to a separate check before doing something, it's extra instructions that always run even when the collection is not empty.
Optimize for the most common case. Instead of adding extra code to slightly speed up the rare empty case, leave it out to speed up the common non-empty case.
I think most loops tend to run on non-empty collections. Small is common for some cases, but empty is usually rare. Perhaps you have a loop that often or usually runs on empty collections, e.g. a rarely-used feature in a program. Then it's worth thinking about optimizing for that case. (Whether this is a useful way to go about it is another matter)
This extra call to collection.isEmpty() might just optimize into the loop condition anyway, if it JIT-compiles to a simple pointer-increment loop over an array, with a start and end pointer both kept in registers. That's the best case, but then the extra source noise is useless and what you would have gotten anyway.
You could argue that if for (String value : collection) doesn't already compile to the most efficient way to loop over a collection, that's the compiler + JVM's fault, and you shouldn't have to make your source ugly for it. That's probably true to a point, although introducing a call to .isEmpty() isn't something a compiler or runtime can do unless they can inline that method to see that it's really checking the same thing an iterator would. But with JIT compilation, everything is available to be inlined.
TL:DR: It's likely that a good JIT compiler doesn't really spend any real work creating an iterator for most simple collections, and there's nothing to be saved.
In other cases, it's still probably better (for performance) not to do this unless your loop usually runs on empty collections, or (even more unlikely) iterator creation is somehow very expensive.
No , you don't have to check for empty. The first iteration will do the trick for you.
iter.hasNext() method will return true/false value. if collection has no element in it then iterator simply returns false on executing statement iter.hasNext() and loop will be terminated gracefully.
It is not necessary to check if the collection is empty. If you are iterating using a for loop or using while loop with iterator, it will not get into the iteration if the collection is empty.
But when you are iterating the collection, you should check whether the collection is not null. It might throw NullPointerException if the collection is null and you try to iterate using loop or iterator.
You need not to check if the collection is empty.
When you're designing the API for a code library, you want it to be easy to use well, and hard to use badly. Ideally you want it to be idiot proof.
You might also want to make it compatible with older systems that can't handle generics, like .Net 1.1 and Java 1.4. But you don't want it to be a pain to use from newer code.
I'm wondering about the best way to make things easily iterable in a type-safe way... Remembering that you can't use generics so Java's Iterable<T> is out, as is .Net's IEnumerable<T>.
You want people to be able to use the enhanced for loop in Java (for Item i : items), and the foreach / For Each loop in .Net, and you don't want them to have to do any casting. Basically you want your API to be now-friendly as well as backwards compatible.
The best type-safe option that I can think of is arrays. They're fully backwards compatible and they're easy to iterate in a typesafe way. But arrays aren't ideal because you can't make them immutable. So, when you have an immutable object containing an array that you want people to be able to iterate over, to maintain immutability you have to provide a defensive copy each and every time they access it.
In Java, doing (MyObject[]) myInternalArray.clone(); is super-fast. I'm sure that the equivalent in .Net is super-fast too. If you have like:
class Schedule {
private Appointment[] internalArray;
public Appointment[] appointments() {
return (Appointment[]) internalArray.clone();
}
}
people can do like:
for (Appointment a : schedule.appointments()) {
a.doSomething();
}
and it will be simple, clear, type-safe, and fast.
But they could do something like:
for (int i = 0; i < schedule.appointments().length; i++) {
Appointment a = schedule.appointments()[i];
}
And then it would be horribly inefficient because the entire array of appointments would get cloned twice for every iteration (once for the length test, and once to get the object at the index). Not such a problem if the array is small, but pretty horrible if the array has thousands of items in it. Yuk.
Would anyone actually do that? I'm not sure... I guess that's largely my question here.
You could call the method toAppointmentArray() instead of appointments(), and that would probably make it less likely that anyone would use it the wrong way. But it would also make it harder for people to find when they just want to iterate over the appointments.
You would, of course, document appointments() clearly, to say that it returns a defensive copy. But a lot of people won't read that particular bit of documentation.
Although I'd welcome suggestions, it seems to me that there's no perfect way to make it simple, clear, type-safe, and idiot proof. Have I failed if a minority of people are unwitting cloning arrays thousands of times, or is that an acceptable price to pay for simple, type-safe iteration for the majority?
NB I happen to be designing this library for both Java and .Net, which is why I've tried to make this question applicable to both. And I tagged it language-agnostic because it's an issue that could arise for other languages too. The code samples are in Java, but C# would be similar (albeit with the option of making the Appointments accessor a property).
UPDATE: I did a few quick performance tests to see how much difference this made in Java. I tested:
cloning the array once, and iterating over it using the enhanced for loop
iterating over an ArrayList using
the enhanced for loop
iterating over an unmodifyable
ArrayList (from
Collections.unmodifyableList) using
the enhanced for loop
iterating over the array the bad way (cloning it repeatedly in the length check
and when getting each indexed item).
For 10 objects, the relative speeds (doing multiple repeats and taking the median) were like:
1,000
1,300
1,300
5,000
For 100 objects:
1,300
4,900
6,300
85,500
For 1000 objects:
6,400
51,700
56,200
7,000,300
For 10000 objects:
68,000
445,000
651,000
655,180,000
Rough figures for sure, but enough to convince me of two things:
Cloning, then iterating is definitely
not a performance issue. In fact
it's consistently faster than using a
List. (this is why Java's
enum.values() method returns a
defensive copy of an array instead of
an immutable list.)
If you repeatedly call the method,
repeatedly cloning the array unnecessarily,
performance becomes more and more of an issue the larger the arrays in question. It's pretty horrible. No surprises there.
clone() is fast but not what I would describe as super faster.
If you don't trust people to write loops efficiently, I would not let them write a loop (which also avoids the need for a clone())
interface AppointmentHandler {
public void onAppointment(Appointment appointment);
}
class Schedule {
public void forEachAppointment(AppointmentHandler ah) {
for(Appointment a: internalArray)
ah.onAppointment(a);
}
}
Since you can't really have it both ways, I would suggest that you create a pre generics and a generics version of your API. Ideally, the underlying implementation can be mostly the same, but the fact is, if you want it to be easy to use for anyone using Java 1.5 or later, they will expect the usage of Generics and Iterable and all the newer languange features.
I think the usage of arrays should be non-existent. It does not make for an easy to use API in either case.
NOTE: I have never used C#, but I would expect the same holds true.
As far as failing a minority of the users, those that would call the same method to get the same object on each iteration of the loop would be asking for inefficiency regardless of API design. I think as long as that's well documented, it's not too much to ask that the users obey some semblance of common sense.
Given the need to loop up to an arbitrary int value, is it better programming practice to convert the value into an array and for-each the array, or just use a traditional for loop?
FYI, I am calculating the number of 5 and 6 results ("hits") in multiple throws of 6-sided dice. My arbitrary int value is the dicePool which represents the number of multiple throws.
As I understand it, there are two options:
Convert the dicePool into an array and for-each the array:
public int calcHits(int dicePool) {
int[] dp = new int[dicePool];
for (Integer a : dp) {
// call throwDice method
}
}
Use a traditional for loop:
public int calcHits(int dicePool) {
for (int i = 0; i < dicePool; i++) {
// call throwDice method
}
}
My view is that option 1 is clumsy code and involves unnecessary creation of an array, even though the for-each loop is more efficient than the traditional for loop in Option 2.
At this point, speed isn't important (insert premature-optimization comment ;). What matters is how quickly you can understand what the code does, which is to call a method dicePool times.
The first method allocates an array of size dicePool and iterates through its values, which happens to run the loop body dicePool times (I'll pretend you meant int instead of Integer to avoid the unrelated autoboxing issue). This is potentially inefficient for the computer running the code, but more importantly it's inefficient for the human reading the code as it's conceptually distant from what you wanted to accomplish. Specifically, you force the reader to think about the new array you've just made, AND the value of the variable a, which will be 0 for every iteration of the loop, even though neither of those are related to your end goal.
Any Java programmer looking at the second method will realize that you're executing the loop body dicePool times with i 'counting up' to dicePool. While the latter part isn't especially important, the beginning is exactly what you meant to do. Using this common Java idiom minimizes the unrelated things a reader needs to think about, so it's the best choice.
When in doubt, go with simplicity. :D
Why would you need to allocate an array to loop over a variable that can be safely incremented and used without any need of allocation?
It sounds unecessarily inefficient. You can need to allocate an array if you need to swap the order of ints but this is not the case. I would go for option 2 for sure.
The foreach is useful when you want to iterate on a collection but creating a collection just to iterate over it when you don't need it is just without sense..
(2) is the obvious choice because there's no point in creating the array, based on your description. If there is, of course things change.
What makes you think that the for-each loop is more efficient?
Iterating over a set is very likely less efficient than a simple loop and counter.
It might help if you gave more context about the problem, specifically whether there's more to this question than choosing one syntax over the other. I am having trouble thinking of a problem to which #1 would be a better solution.
I wouldn't write the first one. It's not necessary to use the latest syntax in every setting.
Your instinct is a good one: if it feels and looks clumsy, it probably is.
Go with #2 and sleep at night.