I am a bit confused on how to utilize Java's Garbage Collection to dispose of instances of objects that aren't in use anymore. I have a few questions:
In my game, I generate Cannons without storing them in a variable like so:
new Cannon("down", tileX, tileY, 65);
Will this object always be eligible for garbage collection? If yes, then when will it actually be disposed of?
==
For my Cannon class, I add all instances to a static array list upon creation. This was my first attempt at using the garbage collection:
ArrayList<Cannon> cannonList = Cannon.getCannons();
for (int i = 0; i < cannonList.size(); i++) {
Cannon c = (Cannon) cannonList.get(i);
c = null;
}
for (int i = 0; i < cannonList.size(); i++) {
cannonList.remove(i);
}
System.gc();
When I set "c = null;", does it make the original Cannon to "null", thus making it eligible for garbage collection, or does it make a new reference c to the object and then setting it to null, making it do nothing at all for me?
==
My Cannon class continuously creates instances of the EnemyProjectile class. The EnemyProjectiles class contains a boolean field called "visible". What is the correct way to dispose of my EnemyProjectile class and make it eligible for garbage collection when "visible" is equal to false?
The joy of using Java, is that memory is managed for you behind the scenes so that, unlike C or C++, you don't have to worry about deconstructing or disposing of objects. When an object is no longer "usable" (as defined by falling out of scope and being unreachable from another active object) then the garbage collector quietly reclaims the space it was occupying.
In Java, you cannot control when objects are garbage collected nor should you try.
Code that depends on a deterministic garbage collection of unused objects will invariably be fragile and difficult to maintain in Java. in part this is because different JVM implementations will garbage collect at different times. System.gc(); is, at best, a suggestion to the JVM that it do garbage collection, but is no guarantee when (or even if) it will happen.
The best thing you can do is design your program so that reference variables have the absolute shortest possible lifespan. Your code is at risk of memory leaks any time a long-lived object retains a reference to a short-lived object (listeners are an example) or when you create data structures that "manage memory" themselves (eg. your own queue or stack implementation).
ArrayList<Cannon> cannonList = Cannon.getCannons();
for (int i = 0; i < cannonList.size(); i++) {
Cannon c = (Cannon) cannonList.get(i);
c = null;
}
for (int i = 0; i < cannonList.size(); i++) {
cannonList.remove(i);
}
System.gc();
In this snippet, there are several issues:
When you use a data structure from the Java Collections API, you should use the interface as the type, not the concrete class. This is by convention, but doing so will keep your code more flexible. Instead of...
ArrayList<Cannon> cannonList = Cannon.getCannons();
write this instead (valid for any class instances that implement the List interface):
List<Cannon> cannonList = Cannon.getCannons();
When possible, you should use the enhanced for-each loop introduced with Java SE 5. It is less error prone. Your for loops should look like this:
for (Cannon c : cannonList) {
c = null; // this for loop actually accomplishes no useful work since
// the reference is null'd as soon as it gets a reference to
// a Cannon object. The reference in your ArrayList is unaffected
// by this assignment
}
cannonList.clear(); // more concise than removing each element from the list.
TL;DR: Garbage collection occurs when it happens. It is non-deterministic. You are never guaranteed when or even if it will happen. Design your Java programs to make your objects eligible for garbage collection at the earliest possible time ... and then don't worry at all about what happens.
Related
I know that Arrays of primitive type are implicitly initialized to 0 in java.
So if I have a code :
public class Foo{
public static void main(String args[]){
int[] arr = new int[50];
for(int i = 0; i < 30; i++){
arr[i] = i;
}
for(int i = 0; i < 30; i++){ // This Line
System.out.println(arr[i]);
}
}
}
I want to know if memory from arr[30] to arr[49] would already have been reclaimed by garbage collector at the line which has the comment?
I want to know if memory from arr[30] to arr[49] would already have been reclaimed by garbage collector at the line which has the comment?
No, absolutely not. The array is a single object. It's either reachable, or it's not reachable... and in this case, it's still reachable.
In a more complex example, if this were a String[], I wouldn't expect the strings referenced by elements arr[30] to arr[49] to be eligible for garbage collection, either. A very smart GC might be able to tell which parts of an array are unused and not include those in GC roots, but I don't think I've ever seen that. (It would have to know that no other code ever had a reference to the array, for one thing. It seems an unusual situation, and therefore one probably not worth optimizing.)
No they would not have been reclaimed - because there is still an active reference to them.
As soon as the garbage collector notices that some objects are not in use anymore, it will mark them for deletion. (A referenced object is an which still has a pointer to it).
After they are marked for deletion - a later cycle of the garbage collection will delete the actual object. This will cause some more free space to appear in those places.
After the objects are deleted - the remaining used space is compacted (so all the empty space sits together, essentially).
I'm new to java. I came through the following code while reading an introductory book on Java while reading about the finalize method.
class FDemo{ int x;
FDemo(int i){
x=i;
}
protected void finalize(){
System.out.println("Finalizing " +x)
}
void generator(int i) {
FDemo o= new FDemo(i);
}
}
Now while creating objects I encountered the following in the new class
int count;
FDemo ob= new FDemo(0);
for (count=1;count<10000000;count++)
ob.generator(count);
I'm having trouble understanding how are we creating new objects using the same name 'o' in the for loop? Would we have to create a new object and then on the next iteration discard the existing object 'o' throughout the loop?
Also, why does finalize execute for 10 million but not for 1000 if we are constantly creating and discarding the same object? Like I said, I'm a beginner and this question might sound very basic or even silly for most of the people here but I would appreciate it very much if you could take out a few minutes to answer.
Thank you
Also, why does finalize execute for 10 million but not for 1000 if we
are constantly creating and discarding the same object
You really create 10 million distinct objects in this applications's lifetime, each of which gets referenced by o , one after the other.
Each time, the de-referenced one becomes eligible for garbage collection, because it has become unreachable from the application, and the garbage collector then calls it's finalize method.
How are we creating new objects using the same name 'o' in the for loop?
You should learn some C and how pointers works, Java hide this, so it can be weird some time.
In Java, there is 2 type of data : objects (like String or your FDemo) and primitives (like int, char...).
Variables that references a primitive works like you intended to, each time you give it a new value, it erase the previous one.
Variables that references objects don't work that way, they are pointers. A pointer can be seen as an address. It's clearer in C (and C++), where they are in fact primitives and can be print as well.
Next come the life time of your variables. When you quit the section where you variable is declared, it's cease to exist (but objects are not automatically destroyed and I think it's the purpose of your exercise).
As example :
public void someMethod() {
int a = 1;
// I have access to a
{ // I create a new section, generally, it's use by condition, loop...
int b = 2;
// Here I have access to a and b
} // End of my section
// b is destroyed, I still have access to a
}
// I'm outside my method, a is destroyed
Why does finalize execute for 10 million but not for 1000 if we are constantly creating and discarding the same object?
That's the purpose of the Java's Garbage Collector. It's a big system used to clean memory. It destroys (call the finalize() method) all object that don't have pointers that references them. It's only called when you really need it, because it can use a lot of processing power (in old machine, applications could freeze when the garbage collector starts).
Your object is very simple (only 1 primitive), so it doesn't use a lot of memory. That's why the garbage collector is called only when you create 10 millions objects.
Ok I'm going to break this up into parts.
How are we creating new objects using the same name 'o' in the for
loop?
So, what you are doing here is actually just overriding/re-assiging the reference variable of o to a differnt FDemo. That leaves the old one empty and eventually gets destroyed by garbage collector. (Which is what invokes the finalize() method)
Would we have to create a new object and then on the next iteration
discard the existing object 'o' throughout the loop?
Well that is exactly what you are doing, when you re assign o you are overwriting the old one.
Also, why does finalize execute for 10 million but not for 1000 if we
are constantly creating and discarding the same object?
Well, this is because java's trash collector is only triggered when a massive amount of objects are made. However, I am surprised that 100000 didn't do it.
The thing you have to remember about finalize(), its only called on the trash collection of the object. Now, thats a very unreliable process and isn't really within your control. Like #TT. said in the comments, dont rely on this. The program that you have written simpliy forces the finalize() method to eventually be invoked due to generating a massive amount of objects intentionally. It's a good way to learn about finalize and how it works, but in practice this may not be a great solution.
Lets say that I'm deleting a "dead" object called "Enemy".
Using something like this:
for(int i = 0; i < enemies.size(); i++)
{
Enemy en = (Enemy) enemies.get(i);
if(en.getVisible() == true)
en.update();
else
enemies.remove(i);
}
Does the object get deleted after being removed from ArrayList? Or "should" it? I've been mainly doing C++ code before and the garbage collection confuses me.
Any way I can see if the objects are being deleted or not by the garbage collector?
Thanks
I really like seeing the opposite of the whole garbage collecting fiasco with C/C++ and Java. Java has it's own garbage collector, you do not need to worry about memory management - .remove() will suffice.
If you remove an object from ArrayList, and that object doesn't have any other reference, then it would be 'eligible' for the garbage collector. After that, you need not worry about removing it from the heap: JVM would do that through automatic garbage collector.
I think it depends on how you entered the object. If you saved it elsewhere it should be still in existence, however if you directly added it to the arrayList it probably is garbage.
P.S. your code needs a correction
enemies.remove(i);
enemies.remove(i--);
Taking my comment about ConcurrentModificationException back. You won't get it, but your loop is still not correct. Take a look:
List<String> list = new ArrayList<String>(Arrays.asList("A","B","C","D"));
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if ("B".equals(s) || "C".equals(s)) list.remove(i);
}
System.out.println(list);
Output:
[A, C, D]
C is not removed due to i always increasing and skipping elements.
For the most part, you won't need to worry about explicit memory management in Java - as long as there are no other objects referring to them after being removed from the list, the garbage collector will (eventually) remove them.
If the objects in the enemies list are holding onto some system resource or something else that needs to be explicitly disposed of (say a file handle or something), you'll want to clean this up before losing the reference:
Enemy enemy = enemies.remove();
enemy.dispose(); // this is your method to clean up the internals - name it what you want
// continue your loop here
On a note related to your sample code, you'll want to use an Iterator rather than just a for loop iterating over the indexes so you can remove properly without running into issues around the current index and list size. You may also want to consider a different List implementation (such as LinkedList, as insert/remove from the middle of an ArrayList can get expensive if it's big.
For your other question:
Any way I can see if the objects are being deleted or not by the garbage collector?
You could override the finalize method of your class - be careful when you do this though. Also note that there are no guarantees when your objects will be garbage collected - different JVMs often manage memory slightly differently, and often only do garbage collection when it needs more memory.
There is no Automatic Garbage Collection in C/C++.
Assume that I wrote a simple program in C/C++ and created a single object.
Assume that there are exactly 10 or extremely limited number of addresses for allocation.
I have a for loop running for 100 times inside which this single object is created every time the loop is run.
In Java, because there is Automatic Garbage collection, after a single loop is executed the address of the object is removed each time automatically.
Rough Example:
for(int i = 0; i < 100; i++)
{
Object o = new Object;
}
In C/C++ we have to manually remove the Object address inside the for loop. Do we have to reboot each time as well to properly remove the Object reference in C++?
For those who say that there are no problems deleting an object more than once in C++. from Wikipedia:
When an object is deleted more than
once, or when the programmer attempts
to release a pointer to an object not
allocated from the free store,
catastrophic failure of the dynamic
memory management system can result.
The result of such actions can include
heap corruption, premature destruction
of a different (and newly created)
object which happens to occupy the
same location in memory as the
multiply deleted object, and other
forms of undefined behavior.
The link: Manual Memory Management
So there IS a risk?
C++ doesn't have (built-in) garbage collection, but that doesn't mean you should let your dynamically allocated memory stay allocated forever. You can and should free it. The most basic way to that would be to free your object reference (or pointer, since this is C++) manually when you don't need it anymore:
for(int i = 0; i < 100; i++)
{
// Dynamically allocate an object
Object* o = new Object();
// do something with object
// Release object memory (and call object destructor, if there is one)
delete o;
}
If you allocated your object on the stack however, it always gets automatically released when it goes out of scope, and you don't have to wait for garbage collection to happen - it's always released immediately:
for(int i = 0; i < 100; i++)
{
// Create a new object on the stack
Object o = Object(); // Note we're not using the new keyword here.
// Do something with object
// Object gets automatically deallocated, or more accurately, in this specific
// case (a loop), the compiler will optimize things, so object's destructor
// will get called, but the object's stack memory will be reused.
}
This behavior of C++ stack values (automatic destruction when they go out of scope), which is awkwardly termed RAII (Resource Acquisition Is Initialization) allows for very nice things that Java just can't do. One of them is smart pointers, that allow dynamically allocated objects to be freed automatically just like their stack counterparts, and you can use sophisticated smart pointers to implement your own version of garbage collection if you want.
Another advantage of RAII is that finally-blocks are rarely necessary in C++: local variables that reference to a resource that should be freed immediately are usually allocated on the stack, and therefore get released automatically. No need for finally blocks here.
Practically speaking, when programming in C++ you'd usually put local variables on the stack (and get all the advantages of RAII without lifting a finger), unless you need to keep them alive for longer than that (e.g. you need to create an object and store a reference to it that stays alive when you leave the function that created the object). In that case, you can use pointers directly, but if you don't want to deal with manually deleting pointers and all the problems it can lead to, you'd usually use a smart pointer. A smart pointer is an object allocated on the stack, that wraps a 'dumb' (i.e. regular) pointer, and deletes the pointer when its destructor gets called. More advanced version of smart pointers can implement reference counting (so the pointed object will be released only when all smart pointers referencing it go out of scope) and even garbage collection. The standard library comes with two smart pointers: auto_ptr and smart_ptr (the latter is reference-counting, but some old compiler may not support it).
Java doesn't automatically remove the object at the end of each loop. Instead it waits until there is a lot of garbage and then goes through and collects it. Java makes no guarantees about how long it will be before the object is collected.
In C++, once the program has exited all resources are returned. You don't need to reboot (assuming a reasonable operating system) in order to make sure that resources are returned. Your operating system will take care of making sure that any resources your program didn't release get released when it is shutdown.
If you delete the object in C++, then its gone right then. you don't have to do anything else to recover the memory.
C++ certainly does have automatic storage duration; it just has other types of storage duration as well, and the ability to choose what is most appropriate.
In something like your example, you would use automatic storage:
for (int i = 0; i < 100; ++i) {
Object o;
// The object is automatically destroyed after each iteration
}
If the object is required to outlive the loop, perhaps because it is passed to another object to manage, then you would use smart pointers (the closest C++ equivalent to Java's references). Here are examples using auto_ptr and shared_ptr:
// some function that takes ownership of an object
void register(auto_ptr<Object> const & o);
void register(shared_ptr<Object> const & o);
for (int i = 0; i < 100; ++i) {
auto_ptr<Object> o(new Object);
register(o); // ownership may be transferred; our pointer is now null in that case
// The pointer is automatically destroyed after each iteration,
// deleting the object if it still owns it.
}
for (int i = 0; i < 100; ++i) {
shared_ptr<Object> o(new Object);
register(o); // ownership is shared; our pointer is still valid
// The pointer is automatically destroyed after each iteration,
// deleting the object if there are no other shared pointers to it.
}
In none of these cases do you need to manually delete the object; that is only necessary when dealing with raw object pointers which, in my opinion, should only be done when absolutely necessary.
C++ also has an advantage over Java here: destruction is always deterministic (that is, you know exactly when it happens). In Java, once an object is discarded, you do not know exactly when (or even if) the garbage collector will remove it. This means that, if the object manages a resource (such as a lock, or a database connection) that needs to be released after use, then it is up to the user of the object to manually release it. In C++, this can be done automatically in the destructor, making the class easier and less error-prone to use.
There is no Automatic Garbage Collection in C/C++.
False. C and C++ don't mandate automatic garbage collection, but it's available anyway (e.g., see the Boehm/Demers/Weiser collector).
In C/C++ we have to manually remove the Object address inside the for loop.
Again, false. In C or C++, we'd define the object using the automatic storage class, which would deterministically destroy the object:
for(int i = 0; i < 100; i++)
{
Object o;
}
Just for example, let's do a quick test, by defining Object something like this:
struct Object {
Object() { std::cout << "Created an Object\n"; }
~Object() { std::cout << "Destroyed an Object\n"; }
};
For the loop above, this generates:
Created an Object
Destroyed an Object
Created an Object
Destroyed an Object
Created an Object
Destroyed an Object
[97 more repetitions of the same pattern removed ]
Do we have to reboot each time as well to properly remove the Object reference in C++?
No, of course not. The fundamental difference between C++ and Java in this respect is that in C++ the object destruction is deterministic, but in Java it's not. Just for example, in C++, the code above must follow exactly the prescribed pattern -- the body of the loop is a block, and the object must be created on entry to the block, and destroyed on exit from the block. In Java, you get no such assurance. It might only destroy the first object after it has allocated 10 or 20. The objects may be destroyed in any order, and there's not really a guarantee that any particular object will be destroyed at all.
That difference isn't always important, but certainly can be. In C++, it's used to support RAII (aka., SBRM -- stack bound resource management). This used to assure not only that memory is freed when no longer needed (i.e., the same thing Java's automatic garbage collector handles) but also that other resources (anything from files to widgets to network or database connections) are handled automatically as well.
If you have short lived objects and performance is critical (most of the time it is not) you can create a mutable object which is reused on each loop. This moves work from a per-iteration to per-loop.
List list = new ArrayList(); // mutable object.
for(int i = 0; i < 100; i++) {
list.clear();
// do something with the list.
}
// one list is freed later.
You can make the list a member field (meaning the mutable object might never be freed), which is fine, provided your class doesn't need to be thread safe.
Assuming you are on a typical operating system (Windows/Linux) - no you do not need to reboot. The OS will protect you via the Process/Virtual Memory structure.
Only your process will run out of memory. The OS will clean up after you when you process ends.
Running on many small embedded systems without an OS - yes you would crash or lockup the processor and require a reboot.
Adding to the already given answers, you can always write signal handlers, upon receiving which you can clean up the memory used by your process..
Normally the OS deallocate your program when you quit it. But some OS might not (I've seen that on a http://www.beck-ipc.com/en/products/sc1x/sc13.asp : RTOS didn't deallocate on exit so I ran out of memory after a couple of launch when I didn't deallocate all my objects, so yes I had to reboot).
But most OS will clear/deallocate previously used programs (linux and windows does), so you shouldn't have to worry.
In the university we were given the following code sample and we were being told, that there is a memory leak when running this code. The sample should demonstrate that this is a situation where the garbage collector can't work.
As far as my object oriented programming goes, the only codeline able to create a memory leak would be
items=Arrays.copyOf(items,2 * size+1);
The documentation says, that the elements are copied. Does that mean the reference is copied (and therefore another entry on the heap is created) or the object itself is being copied? As far as I know, Object and therefore Object[] are implemented as a reference type. So assigning a new value to 'items' would allow the garbage collector to find that the old 'item' is no longer referenced and can therefore be collected.
In my eyes, this the codesample does not produce a memory leak. Could somebody prove me wrong? =)
import java.util.Arrays;
public class Foo
{
private Object[] items;
private int size=0;
private static final int ISIZE=10;
public Foo()
{
items= new Object[ISIZE];
}
public void push(final Object o){
checkSize();
items[size++]=o;
}
public Object pop(){
if (size==0)
throw new ///...
return items[--size];
}
private void checkSize(){
if (items.length==size){
items=Arrays.copyOf(items,2 * size+1);
}
}
}
The pop method produces the memory leak.
The reason is that you only reduce the number of items that are in the queue, but you don't actually remove them from the queue.The references remain in the array. If you don't remove them, the garbage collector, won't destruct the objects, even if the code that produced the object is executed.
Imagine this:
{
Object o = new Object();
myQueue.add(o);
}
Now you have only one reference for this object - the one in the array.
Later you do:
{
myQueue.pop();
}
This pop doesn't delete the reference. If you don't remove the reference the Garbage collector will think that you are still thinking of using this reference and that this object is useful.
So if you fill the Queue with n number of objects then you will hold reference for these n objects.
This is a the memory leak your teachers told you about.
Hint: the leak is in the pop method. Consider what happens to the references to a popped object ...
It's not a priori true that there's a memory leak here.
I think the prof has in mind that you're not nulling out popped items (in other words, after you return items[--size], you probably ought to set items[size] = null). But when the Foo instance goes out of scope, then everything will get collected. So it's a pretty weak exercise.
This example is discussed in Effective Java by Joshua Bloch. The leak is when popping elements. The references keep pointing to objects you don't use.
The code sample doesn't produce a leak. It's true that when you call pop(), the memory isn't freed for the appropriate object - but it will be when you next call push().
It's true that the sample never releases memory. However, the unreleased memory is always re-used. In this case, it doesn't really fit the definition of memory leak.
for(int i = 0; i < 1000; i++)
foo.push(new Object());
for(int i = 0; i < 1000; i++)
foo.pop();
This will produce memory that isn't freed. However, if you ran the loop again, or a hundred thousand million times, you wouldn't produce more memory that isn't freed. Therefore, memory is never leaked.
You can actually see this behaviour in many malloc and free (C) implementations- when you free memory, it isn't actually returned to the OS, but added to a list to be given back next time you call malloc. But we still don't suggest that free leaks memory.
Memory leaks are defined as unbounded growth in allocation caused by ongoing execution.
The explanations provided explain how objects could continue to be held active through references in the stack after popping, and can certainly result in all kinds of misbehaviour (for example when the caller releases what they think is the last reference and expects finalisation and memory recovery), but can hardly be called leaks.
As the stack is used to store other object references the previous orphaned objects will become truly inaccessible and be returned to the memory pool.
Your initial skepticism is valid. The code presented would provide bounded memory use growth with convergence to a long-term state.
Hint: Imagine what happens if you use a Foo object, insert into it 10000 "heavy" items, and then remove all of them using pop() because you don't need them anymore in your program.
I'm not going to flat out give you the answer, but look at what push(Object o) does that pop() doesn't do.
In the pop() method, the item on the size (i.e, items[size-1]) is not set to NULL. As a result, there still exists reference from objects items to items[size-1], although size has been reduced by one. During GC, items[size-1] won't be collected even if there is no other object pointing to it, which leads to memory leak.
Consider this demo:
Foo f = new Foo();
{
Object o1 = new Object();
Object o2 = new Object();
f.push(o1);
f.push(o2);
}
f.pop();
f.pop();
// #1. o1 and o2 still are refered in f.items, thus not deleted
f = null;
// #2. o1 and o2 will be deleted now
Several things should be improved in Foo which will fix this:
In pop, you should set the items entry to null.
You should introduce the opposite to checkSize, something like shrinkSize, which will make the array smaller (maybe in a similar way to checkSize).