Dima - Memory Management

Monkey Forums/Monkey Programming/Dima - Memory Management

Raz(Posted 2011) [#1]
Hi Dima, hopefully you (or someone else) can offer some advice, in the memory management thread you said the following
I take bullet #10 (last active), and swap pointers with #3, so bullet 10 is located where 3 used to be in the array


Is there a clever way of doing this swap? My code does the following which essentially stores A in Temp, moves B to A and then moves Temp to B

Function Remove:Void(i:Int)
	Local tempItem:ThirdTest = Items[i]
	Items[i] = Items[NextActive]
	Items[NextActive] = tempItem
End



Skn3(Posted 2011) [#2]
My only addition to that would be if you are doing a ton of swaps then pre allocate the temporary swap pointer, somewhere in your app/parent object. You can then reuse it all over the place.

I would like to know if thats good practice actually?

I tend to have soem generic temp values that are allocated at start of scene and then reused in all places that require temp "things".. I dunno if that has issues with how the values are pulled up internally? My assumption was that the garbage collector wouldnt keep having to kick in with collection or continusously recreated temporary "things".. ?


Raz(Posted 2011) [#3]
That sounds like a good idea to me Skn3 :)


dmaz(Posted 2011) [#4]
generally that's not a good idea... first don't waste your time for those optimizations as they usually don't amount to much anyway. second, the compiler has more ability to optimize/cache local variables so they are most often faster anyway. third, to know for sure you need to test on each platform you're deploying to.


clevijoki(Posted 2011) [#5]
Unless you are using 'new' you will not be doing anything that affects the garbage collector. Storing an arbitrary temporary reference is actually much worse than using a local temporary reference, because you could prevent things from garbage collecting if you didn't clear that temp reference. And then it's actually slower because now you have to clear a temp reference where before it would disappear when it went out of scope.


Skn3(Posted 2011) [#6]
Interesting well the temporary lists and arrays I guess I'll keep and wipe out after but the general local variables it seems its more worthwhile to just trash.

http://stackoverflow.com/questions/3561457/keep-a-global-variable-or-recreate-a-local-variable-in-c

Time to do some code editing!


clevijoki(Posted 2011) [#7]
Honestly unless you are 100% sure how the virtual machine works, you shouldn't even attempt to optimize for it. You will only get incremental optimization gains by doing small tweaking like this, and if you don't know what you are doing you could get performance losses and serious stability problems.

Furthermore it is possible to use analysis on variables to remove heap allocations:
http://stackoverflow.com/questions/1791115/jvm-and-clr-allocation-optimization

99% of the time, performance problems are caused by design flaws. If your game is running slow perhaps you are doing something that is causing excessive calculations and a better overall design will solve this rather than tiny optimizations. For example, using BSP to do collisions will be faster than checking every polygon in the world.


Skn3(Posted 2011) [#8]
I had thought it would be good programming practice to not be wasteful with allocations but made the mistake of bundling in my code convention that an object allocation is the same as just letting a local variable exist!

Brain has been patched. Thanks :D (sorry for topic hijack)


Raz(Posted 2011) [#9]
Soooo...

Function Woop:Void()
Local this:Thing = New Thing()
End


= bad with allocation of new object

Function Woop:Void(i:Int)
Local this:Thing = ThingArray[i]
End


= good, because the only new allocation is a pointer.


FlameDuck(Posted 2011) [#10]
I would like to know if thats good practice actually?
Yes. In fact Google even recommends doing it this way.


dmaz(Posted 2011) [#11]
Yes. In fact Google even recommends doing it this way.
where do they say that in that page?


FlameDuck(Posted 2011) [#12]
The sections about "Avoid Creating Unnecessary Objects" and "Prefer Static Over Virtual".


dmaz(Posted 2011) [#13]
right, but Skn3 wasn't talking about object allocation, just using a global instead of local for the swap variable in the OP example, unless I read that wrong? Prefer Static Over Virtual refers to methods not variables on registers or the stack.


clevijoki(Posted 2011) [#14]
The only real memory optimization you need to do on all garbage collected languages is avoid creating short-term objects. The optimization I posted earlier with escape analysis that removes these short term allocations is not actually done by google's vm right now. That means you still need to do some hackery.

Generally you want to avoid ALL short term memory allocation in games, which means storing object instances you would normally want in the body of a function in the class or as globals.

Monkey has all the information it needs to do this internally, and it should change it's output to use object pools.


AdamRedwoods(Posted 2011) [#15]
Angelfont uses too many short-term object allocations. When run on Android you can see a drastic slowdown.

You can optimize Angelfont so it recycles objects and avoids recreating/destroying objects in loops.

Not only that, but using an character IntMap rather than a StringMap will also improve it's efficiency since Strings are objects that are created/destroyed when operated on.


dmaz(Posted 2011) [#16]
ok, I think we all agree that object creation is best avoided. but
Generally you want to avoid ALL short term memory allocation in games, which means storing object instances you would normally want in the body of a function in the class or as globals.

so clev and adam, are you guys are saying that
globalSwpVar = alreadyCreatedMyObject
performs better than
local localSwpVar:myObject = alreadyCreatedMyObject
because that is NOT correct... the local will almost always perform better. do you have evidence or a link that shows the global is faster?


AdamRedwoods(Posted 2011) [#17]
Global will not always perform faster.

But..
Class myclass
  Global set:List<object> = New List<object>
  Global swpvar:object ''you could use Field here too

  Method Sort()
    For swpvar = Eachin set
      swpvar.DoSomething()
    Next
  End
End


This will prevent a lot of object allocation/deallocation for the garbage collector, which can slow down performance. With Java(android) and XNA this type of optimization is needed for performance.

PLUS (correct me if I'm wrong) Global within a Class may be converted to a static variable when trans-coded to Java-- which is recommended for performance.


Skn3(Posted 2011) [#18]
So a field in an already created object is considered a local or a global? (I always thought it was treated the same as a local)

If you were to have a general purpose instance pointer contained as a field and then used by the methods belonging to the container; as long as you managed the null-ing of said pointer.. would this be worth while or is it still just better off to create potentially hundereds/thousands temporary local pointers per update?

Im sure the performance increase (if any?) is going to be small but it would be interesting to know...


dmaz(Posted 2011) [#19]
I have to disagree... everything I read and have tested show that globals seldom perform faster than local variables even is situations where you are "allocating" them millions of times in the loop. the reason is that "allocating" standard plain old data types like ints or doubles is basically free since they go on the stack. I quoted allocating, because no memory is being allocated at all with local plain datatypes and since they are only on the stack the GC doesn't even get involved since that frame/scope is just pulled from the stack. have you actually done a poof/test? I'll bet 1 US dollar that your example would be the same speed or faster if written like this. although, the difference will be very small... which is again why I say this is not something to worry about. The reason it would be faster is there's better chance it will all be closer to the cpu (on registers or in the l1)
Class myclass
  Global set:List<object> = New List<object>

  Method Sort()
    For Local swpvar:object = Eachin set
      swpvar.DoSomething()
    Next
  End
End
later today I might be able to write up a test case...?


AdamRedwoods(Posted 2011) [#20]
In my opinion, it really depends on the programming language.
Local Ints, Floats, are faster than global Ints, Floats for most cases.

But with objects and classes, it's a different story.

The biggest difference I encountered this was with AngelFont. I managed to get 2 fps more (on Android) by moving objects to an allocated pool rather than creating them in local loops. This is mostly because of the garbage collection.

I don't know if a test case will pronounce the effects as well as Angelfont can.

Test case:


On my PC, the results are at times identical, but local is faster by 1-2 ms.

On the Android, the results fluctuate (takes about 12-14 secs to run the test cases ), but the results lean in the allocated object's favor by a 10-20 millisecs.

Yes, for general use there's no need to worry about these performance tweaks.


Samah(Posted 2011) [#21]
@dmaz
Using EachIn in Android will create an enumerator instance, thus triggering the GC. I'm sure Mark could optimise this somehow (caching enumerators maybe?)