Sanxion
Junior Devvie  
Java games rock!
|
 |
«
Posted
2003-11-22 19:48:14 » |
|
I have an application that seems to gallop away in terms of RAM usage. I think it has to do with cleaning up references.
Is there any way to loop thru the fields of an instance and set them to null?
It would be a start if i could do this on my custom delete() method, to stop circular references.
|
|
|
|
cfmdobbie
Senior Devvie    Medals: 1
Who, me?
|
 |
«
Reply #1 - Posted
2003-11-22 21:21:33 » |
|
Java doesn't suffer from circular references in the way you might expect - two objects mutually referring to one another won't stop both of them being collected as garbage if noone else can access them. Java uses a reachability check to guarantee this. There is a "sort-of" delete() method in Java, called finalize(). It is called exactly once before first garbage collecting an object, and allows the developer to perform any cleanup required. However, it is rarely used and is unlikely to be what you're after here. If you allocate lots of new objects, Java will likely use RAM up (without freeing old objects) until it isn't allowed any more - there's no point in performing any collection unless there's a need for it, after all. Are you actually getting OutOfMemoryErrors, or are things just using up more memory than your system is comfortable with? Take a look at the command-line JVM flags if you do wish to modify Java's memory settings. Edit: "Out of memory" is an *error*, not an *exception* 
|
Hellomynameis Charlie Dobbie.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Jeff
|
 |
«
Reply #3 - Posted
2003-11-23 02:37:04 » |
|
And use a profiler to see if your objects are really still "anchored" and referenceable.
Memory leaks can't happen in Java, but what we call "Object Leaks", which are user-error in leaving an object refrenceable, happen more often then people realize.
Also be sure to close any system objects which have a close() (or dispose() ) method that you are using when done with them. Some of our API implementations hang onto references in inobvious ways. (For instance, you need to close an ObjectOutputStream or it keeps a reference to every object written to it.)
|
|
|
|
Sanxion
Junior Devvie  
Java games rock!
|
 |
«
Reply #4 - Posted
2003-11-23 11:09:40 » |
|
Okay.
I have an instance of Car. Car has a reference to Engine. Engine has a reference to Car.
I am done with the Car. I set the Engine in car to null. If I understand things correctly the Car will not be garbage collected as long as the Engine has a reference to it?
|
|
|
|
kevglass
|
 |
«
Reply #5 - Posted
2003-11-23 11:16:36 » |
|
Only if something else is holding a reference to the Engine. If nothing else does, Engine will get collected which in turn will mean that nothing is left to point to Car, and hence it will get collected.
Kev
|
|
|
|
princec
|
 |
«
Reply #6 - Posted
2003-11-23 11:27:54 » |
|
The gap in Sanxion's knowledge here is that an object is collected if it cannot be reached by any Thread by traversing all references - not that it cannot be reached by any other object. Cas 
|
|
|
|
Sanxion
Junior Devvie  
Java games rock!
|
 |
«
Reply #7 - Posted
2003-11-23 11:51:12 » |
|
Bridges are being built in Sanxions mind!
|
|
|
|
Jeff
|
 |
«
Reply #8 - Posted
2003-11-23 19:00:47 » |
|
Clearly you are used to a reference counting solution to determining garbage. In reference counting, circular references are an issue because each one keeps the other alive.
(It's worth noting though that even in your car-engine case above, as soon as you break one link in the circle, its not a problem. Car references Engine. Engine references car. That will stay around in reference counting situation because both objects have a count of one. if however you null Car's reference to Engine, Engines count drops to 0. Engine is freed. When Engine is free ITS reference to Car goes away so Car's count drops to 0 and Car is also freed.)
HOWEVER reference counting is a very primitive soulutions for garbage detection. More sophisticated solutions (such as used by Java) actually trace reference trees back to "root" objects that process can start a reference chain from (eg static variables, class variables, instance variables or temporary variables currently active on the stack.) If the object is not reachable from one of them, it is marked as garbage and eventually collected.
In your earlier example, if Car or Engine were an object instance variable then both would stay HOWEVER if your object instance contained a list of cars, that was the only "root" reference to Car, there were no "root" references to Engine except through Car, and you removed Car from the List, Car AND Engine would get marked as garbage and, should the need for memory arise, collected.
See?
|
|
|
|
John
Junior Newbie
|
 |
«
Reply #9 - Posted
2003-11-24 16:14:21 » |
|
A couple of points on cleanup we follow, after some experience cleaning up memory in a medium sized application ...
- nulling out variables is bad. It can convey state, it can be used to trigger lazy instantiation, but as a general rule it leads to null pointers. It has never fixed a memory leak for me, but it has minimized the scope of a memory leak. (see point below). Where state info is desired there is always a better way, especially if you're masking an exception. Threadsafe objects tend to be immutable, so this is more possible & desirable than you might think.
- Minimizing the impact of a leak I think is a valid reason to set things to null, some object trees are huge. A better solution for minimizing the scope of a leak would be to use an empty object aka MyBigClass.NULL_OBJECT. It's the same thing as passing around empty arrays instead of null objects, things break less and the size of leaks are minimized. I would only employ this strategy on items with potential for big leaks.
- oh yeah, don't touch finalize with a ten foot pole. If you can find another way use it. Overriding any method that is only called 1/3 of the time is asking for trouble.
Memory cleanup is important, and should be designed in. What I look for in a class cleanup ....
1. It has one of dispose(), cleanUp() or add/removeNotify(). .. although I recommend against the last option, no one seems expect the override of the notify methods, and so they are never maintained right.
2. It removes all listeners, it empties all collections and arrays, closes any I/O streams, it can be called safely multiple times (important! no one should be afraid to call cleanup methods).
My 2 cents ...
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Sanxion
Junior Devvie  
Java games rock!
|
 |
«
Reply #10 - Posted
2003-11-24 17:01:56 » |
|
Okay, I do my cleanup in a delete() method. Btw to empty Collections do you: myArrayList = new ArrayList(); OR myArrayList=null 
|
|
|
|
Jeff
|
 |
«
Reply #11 - Posted
2003-11-24 17:58:40 » |
|
Btw to empty Collections do you: myArrayList = new ArrayList(); OR myArrayList=null  Neither. myArrayList.clear() is the way to empty it. The other two turn it into garbage to be collected which probably isnt what you want in most instances. (The clear() method and many other wonders can be found by keeping and using a copy of the API docs on your workstation  )
|
|
|
|
Jeff
|
 |
«
Reply #12 - Posted
2003-11-24 18:00:33 » |
|
I should note that this entire thread really belongs in the "Newless Clubies" topic, not the performance topic.
|
|
|
|
erikd
|
 |
«
Reply #13 - Posted
2003-11-30 16:49:30 » |
|
I should note that this entire thread really belongs in the "Newless Clubies" topic, not the performance topic.
Agreed  .
|
|
|
|
ENC
|
 |
«
Reply #14 - Posted
2006-10-27 00:57:52 » |
|
Ok... if I get everything right.. as long the object is not reference by the root of the thread in the JVM. It will be garbage collected right? I have two questions: Can we alter the timing of when the JVM starts its garbage collection. Meaning if every five minutes it will do garbage collection, then can I alter it to be do it every 2 minutes instead? Next is, my game logic always change an object instance to null first before newing an new instance of the same object Example: 1 2 3 4 5
| A a = new A();
A a = null;
A a = new A(); |
But for some reason, the game lags alot after 10 mins of gameplay.. is this something to do with the JVM? Cheers!
|
|
|
|
darkprophet
Senior Devvie   
Go Go Gadget Arms
|
 |
«
Reply #15 - Posted
2006-10-27 01:34:22 » |
|
The finalize() method has now been superseeded by the Reference classes, use them instead to get some sort of cleanup...
Regarding GC timing, you can't alter it at the moment, you can only hint at it by calling System.gc();
|
|
|
|
ryanm
|
 |
«
Reply #16 - Posted
2006-10-27 02:41:54 » |
|
Can we alter the timing of when the JVM starts its garbage collection.Meaning if every five minutes it will do garbage collection, then can I alter it to be do it every 2 minutes instead?
The short, flippant, answer is: Sure, reduce the size of the Java heap and the GC will run more frequently. The longer, and probably more correct, answer is: Control of the GC is probably best left to the JVM. Feel free to call System.gc() between levels or in some similar game down-time, it's only a suggestion to the JVM and it can't hurt. Worrying about precisely when a full GC will occur is counter-productive... unless you have profiled extensively and you know for a fact that the GC is a problem for you. As to explicitly null-ing object references: It can't hurt and it probably makes the intent of your code more obvious. I doubt, however, that it has a huge impact on performance. Note that I am in no way a JVM engineer, and so speak with no authority on this matter. The JVM does seem to optimise the most clear method of doing things (witness object pooling: used to be a necessary evil, now considered just plain evil in most cases), so write your game in the most clear and expressive way possible for now. Optimise proven bottlenecks later.
|
|
|
|
Don Kiddick
|
 |
«
Reply #17 - Posted
2006-10-27 03:46:25 » |
|
I believe nullifying references is slower than letting them fall out of scope as you have an extra set performed in memory. Would have to check the bytecode produced but O thinl it is true
|
|
|
|
erikd
|
 |
«
Reply #18 - Posted
2006-10-27 14:52:27 » |
|
Nullifying references is not needed except in some rare cases involging the allocation of huge amounts of memory:
(Having a heap of 64MB)
int[] array = new int[60MB worth of integers]; array = new [60MB worth of integers];
this will throw a OutOfMemoryError because the array allocated in the first line is not garbage collectable at the 2nd line. Inserting array=null; between the 2 lines will prevent this from happening.
In all other cases, nullifying doesn't really make a difference as far as I know.
|
|
|
|
ENC
|
 |
«
Reply #19 - Posted
2006-10-30 00:22:07 » |
|
(Having a heap of 64MB)
int[] array = new int[60MB worth of integers]; array = new [60MB worth of integers];
So If I get you right... int[] array = new int[60MB worth of integers]; array = null <-- GC will occour at this line is it? or does it GC after the new object which is at the next line? array = new [60MB worth of integers]; Curious
|
|
|
|
Jackal von ÖRF
|
 |
«
Reply #20 - Posted
2006-10-30 06:00:07 » |
|
int[] array = new int[60MB worth of integers]; array = null <-- GC will occour at this line is it? or does it GC after the new object which is at the next line? array = new [60MB worth of integers];
GC happens when the allocation of the second array is started, and the VM notices that there is not enough memory to allocate it. No GC happens at the "array = null" line itself. It just removes the reference to the array, and the array will stay in memory for an undefined time before it is collected.
|
|
|
|
|