How many objects will be eligible for garbage collection? - java

So I've recently been to job interview and was asked the following question. (Actually it was just a test writing, so I couldn't ask any questions)
At the end of the main method, how many objects will be eligible for garbage collection?
public class Main {
public static void main(String[] args) {
Object obj;
for (int i = 0; i < 5; i++) {
obj = new Object();
}
obj = null;
}
}
(A) 0
(B) 1
(C) 5
I know it's 0 because at least one object (obj) will be garbage collected, but I also know that obj is not really the object, it's just a reference to it. So my answer was 5.
Is that correct? If not, then why?

Your answer 5 is correct.
Here total 5 number of objects are created through for loop and all of these will be eligible for garbage collection at the end of the method.

Probably 0,
The compiler might workout some optimisation and eliminate the entire loop and avoid creating the five objects created in the loop in the first place.
So if no compiler optimisation is going on, 5 objects are created inside the loop and their references is being overwritten in the variable obj, at the end variable will reference the last object which is being assigned to null.

Related

How to delete object inside method? [duplicate]

I want to delete an object I created, (a oval which follows you), but how would I do this?
delete follower1;
didn't work.
EDIT:
Okay, I'll give some more context. I'm making a small game with a oval you can control, and a oval which follows you. Now I've got files named: DrawPanel.class, this class draws everything on the screen, and handles collisions, sounds, etc. I got an enemy.class, which is the oval following the player. I got an entity.class, which is the player you can control. And if the player intersects with the follower, I want my player object to get deleted. The way I'm doing it:
public void checkCollisions(){
if(player.getBounds().intersects(follower1.getBounds())){
Follower1Alive = false;
player.health = player.health - 10;
}
}
You should remove the references to it by assigning null or leaving the block where it was declared. After that, it will be automatically deleted by the garbage collector (not immediately, but eventually).
Example 1:
Object a = new Object();
a = null; // after this, if there is no reference to the object,
// it will be deleted by the garbage collector
Example 2:
if (something) {
Object o = new Object();
} // as you leave the block, the reference is deleted.
// Later on, the garbage collector will delete the object itself.
Not something that you are currently looking for, but FYI: you can invoke the garbage collector with the call System.gc()
Your C++ is showing.
There is no delete in java, and all objects are created on the heap. The JVM has a garbage collector that relies on reference counts.
Once there are no more references to an object, it becomes available for collection by the garbage collector.
myObject = null may not do it; for example:
Foo myObject = new Foo(); // 1 reference
Foo myOtherObject = myObject; // 2 references
myObject = null; // 1 reference
All this does is set the reference myObject to null, it does not affect the object myObject once pointed to except to simply decrement the reference count by 1. Since myOtherObject still refers to that object, it is not yet available to be collected.
If you want help an object go away, set its reference to null.
String x = "sadfasdfasd";
// do stuff
x = null;
Setting reference to null will make it more likely that the object will be garbage collected, as long as there are no other references to the object.
You don't need to delete objects in java. When there is no reference to an object, it will be collected by the garbage collector automatically.
You can remove the reference using null.
Let's say You have class A:
A a = new A();
a=null;
last statement will remove the reference of the object a and that object will be "garbage collected" by JVM.
It is one of the easiest ways to do this.
Java has a Garbage Collector, it will delete the object for you if no reference is held to it anymore.
//Just use a List
//create the list
public final List<Object> myObjects;
//instantiate the list
myObjects = new ArrayList<Object>();
//add objects to the list
Object object = myObject;
myObjects.add(object);
//remove the object calling this method if you have more than 1 objects still works with 1
//object too.
private void removeObject(){
int len = myObjects.size();
for(int i = 0;i<len; i++){
Objects object = myObjects.get(i);
myObjects.remove(object);
}
}

Delete Reference of Inner Class [duplicate]

I want to delete an object I created, (a oval which follows you), but how would I do this?
delete follower1;
didn't work.
EDIT:
Okay, I'll give some more context. I'm making a small game with a oval you can control, and a oval which follows you. Now I've got files named: DrawPanel.class, this class draws everything on the screen, and handles collisions, sounds, etc. I got an enemy.class, which is the oval following the player. I got an entity.class, which is the player you can control. And if the player intersects with the follower, I want my player object to get deleted. The way I'm doing it:
public void checkCollisions(){
if(player.getBounds().intersects(follower1.getBounds())){
Follower1Alive = false;
player.health = player.health - 10;
}
}
You should remove the references to it by assigning null or leaving the block where it was declared. After that, it will be automatically deleted by the garbage collector (not immediately, but eventually).
Example 1:
Object a = new Object();
a = null; // after this, if there is no reference to the object,
// it will be deleted by the garbage collector
Example 2:
if (something) {
Object o = new Object();
} // as you leave the block, the reference is deleted.
// Later on, the garbage collector will delete the object itself.
Not something that you are currently looking for, but FYI: you can invoke the garbage collector with the call System.gc()
Your C++ is showing.
There is no delete in java, and all objects are created on the heap. The JVM has a garbage collector that relies on reference counts.
Once there are no more references to an object, it becomes available for collection by the garbage collector.
myObject = null may not do it; for example:
Foo myObject = new Foo(); // 1 reference
Foo myOtherObject = myObject; // 2 references
myObject = null; // 1 reference
All this does is set the reference myObject to null, it does not affect the object myObject once pointed to except to simply decrement the reference count by 1. Since myOtherObject still refers to that object, it is not yet available to be collected.
If you want help an object go away, set its reference to null.
String x = "sadfasdfasd";
// do stuff
x = null;
Setting reference to null will make it more likely that the object will be garbage collected, as long as there are no other references to the object.
You don't need to delete objects in java. When there is no reference to an object, it will be collected by the garbage collector automatically.
You can remove the reference using null.
Let's say You have class A:
A a = new A();
a=null;
last statement will remove the reference of the object a and that object will be "garbage collected" by JVM.
It is one of the easiest ways to do this.
Java has a Garbage Collector, it will delete the object for you if no reference is held to it anymore.
//Just use a List
//create the list
public final List<Object> myObjects;
//instantiate the list
myObjects = new ArrayList<Object>();
//add objects to the list
Object object = myObject;
myObjects.add(object);
//remove the object calling this method if you have more than 1 objects still works with 1
//object too.
private void removeObject(){
int len = myObjects.size();
for(int i = 0;i<len; i++){
Objects object = myObjects.get(i);
myObjects.remove(object);
}
}

Can variable of nested static class be garbage collected?

In Java, having a nested static class Human, I'm wondering if after cleanup of the map variable can make it available for garbage collected. At the moment just before doSomeCode() I called System.gc() and added Thread.sleep(60000) to wait for garbage collector to pick up unreferenced map contents, but no way - it seems map lives in a program unless it is going to finish. My problem is that I need to free up memory because otherwise will get OutOfMemoryError.
What do you think prevents map property of Human class from being recycled? Is it because the Human class is static and thus all its members can not be garbage collected?
import java.util.List;
import java.util.ArrayList;
import com.carrotsearch.hppc.IntObjectMap;
import com.carrotsearch.hppc.IntObjectOpenHashMap;
public class TestNestedStaticClass {
public static class Human {
String name = null;
List<Human> children = null;
// some data about family members
IntObjectMap<int[]> map = null;
public Human(String name) { this.name = name; }
}
public static void main(String[] args) {
final List<Human> family = new ArrayList<Human>();
for (int i = 0; i < 1000; i++) {
// create and get the family member
family.add(new Human("givenName"));
Human h = family.get(i);
// create map and add some data
h.map = new IntObjectOpenHashMap<int[]>();
for (int j = 0; j < 100; j++) {
int[] array = new int[1500];
h.map.put(j, array);
}
}
// ...
// at some point we want to free the memory occupied by
// family.get(i).map for all i from 0 to 1000, so we do:
for (int i = 0; i < 1000; i++) {
// get the family member
Human h = family.get(i);
// explicitly remove references from the map
for (int j = 0; j < 100; j++) {
h.map.remove(j);
}
// cleanup
h.map.clear();
h.map = null;
}
// ...
doSomeCode();
}
}
From the point where you write: h.map = null;, the map becomes eligible for GC (the removes and clear are technically not necessary).
The reason why you don't see it being GC'ed is possibly due to the fact that you run all that code within the same method, and the GC does not have to collect local variables until the method exits.
If you try to split it in several method it will help the GC (which will get rid of the local variables once the methods exit).
See also this post.
ps: I assumed that you don't have any references to the content of the map or the map itself anywhere else!
The fact that the Human class is static means nothing - and even if the map variable was static, setting it to null frees up the object content for garbage collection.
If you are running into OutOfMemoryErrors, and you are certain the map contents are the cause, then there must be lingering references to the data somewhere. For example, if I do this:
human.map.put(0, new int[10000]);
something.thing = map.get(0);
human.map.remove(0);
human.map = null;
Note that a reference to the int[10000] still remains in memory, #something.thing. Cleaning up the map is only part of the work needed to free up the array for garbage collection.
Note that inner static classes are indeed top classes but just inside a class, so the GC rules to collect their instances are the same rules that GC applies on a common class instance.
There is no need to sleep after System.gc() - the gc method doesn't return until the garbage collector is finished.
An instance of a static inner class is treated the same as an instance of any other class for purposes of garbage collection. You are correctly freeing the map elements of your Human classes (although it's overkill to call map.remove() and map.clear() and map = null - only map = null is needed)
It looks like you are using all primitive data types. This might be a problem, this is just a theory, and I haven't tested it, but it might be worth a try.
Instead of using an array of int's ( int[] ), try using an ArrayList. This should create objects which can be garbage collected, primitive data types are created on the stack not on the heap of objects, therefore they aren't subject to garbage collection?
NOTE: I put a question mark, because I am not positive, someone can confirm or reject my theory.
THEORY REJECTED :( , LEAVING AROUND FOR OTHERS TO READ
1) Been a while since I programmed in Java but my guess is the static objects/variables live on in a special place during whole execution of the program.
2) Calling GC explicitly doesn't ensure the objects will be deleted. You simply call the GC and it decides itself (and you cannot really affect this behavior).

when object will be eligible for garbage collecion

A method given to me and asked, when it will be eligible for Garbage Collection, i mean at which line. I believe both o and oa are eligible for garbage collection. Since, they are set to null. Please correct me, if i'm wrong. But, the question was, when it will be eligible for gc, i mean at which line. ?
public Object m() {
Object o = new Float(3.14F);
Object[] oa = new Object[1];
oa[0] = o; /* Line 5 */
o = null; /* Line 6 */
oa[0] = null; /* Line 7 */
return o; /* Line 8 */
}
Please anyone explain. ?
Let us walk through the code:
1) o = new Float();
2) oa = new Object[];
at this point we have 2 objects.
3) oa[0] = o;
at this point oa[0] holds the reference of o.
4) o = null;
o is still being referenced by oa[0]
5) oa[0] = null
o now has zero references.
6) return o;
o is null.
Line 7 is where the GC eligibility happens for o. oa is not eligible for GC until the function exits.
In general, an object is only eligible for GC when there are no references left to it. Be very careful when dealing with a String as there is a special place called the String pool. So the following code:
void foo()
{
String s = "foo";
s=null;
return s;
}
At no point is s guaranteed to be eligible in the function.
Question from comments
one question, you said..oa is not eligible for GC until the function
exits. but, before the return o, oa set to be null and it nowhere
referred too
Answer:
oa is not set to null. What gets set to null is the object at oa[0]
(the first index of oa). If the line was oa = null that would be true,
and irrespective of the only item in oa being null, does not in fact
make the wrapper (in this case an array) null. Similar to having a
List and nulling out all of its elements does not make the List null.
Java is allowed to do certain optimizations, so an optimizing JIT that reasons only about local-effects could simplify this code to
public Object m() {
//Object o = // o does not participate in any externally visible side-effect
new Float(3.14F); // Available for collection as soon as ctor finishes.
//Object[] oa = new Object[1]; // Array ctors are known not to have side-effects, and oa does not participate in a side-effect or result that is visible outside the method.
//oa[0] = o; /* Line 5 */ // Side-effect not visible.
// o = null; /* Line 6 */ // Side-effect not visible.
//oa[0] = null; /* Line 7 */
//return o; /* Line 8 */ // Eliminated by inlining.
return null; // Type-analysis proves that this method can only return null.
}
Don't assume that assignments of local variables to null actually happen in long-lived method calls.
Garbage collection is eligible when no reference to that object exists any longer, but it can be important to note that GC is not guaranteed to run at that time, so technically the memory can be allocated.
oa[0] refers to the object, so when you set it to null at line 7, no reference to that object exists any longer, so it is eligible for GC.
As pointed out on comments, oa, the array itself, is still around until the method is done executing, i.e. after line 8 executes. It is local to the lifetime of the method m(), so it will be eligible for GC when m() returns from execution.
Please correct me, if i'm wrong. But, the question was, when it will be eligible for gc, i mean at which line. ?
The question is nonsensical or based upon an over-simplified model of garbage collection. Garbage collectors act at run-time on the available representation which means tracing reachability from global roots including the registers, stack and global variables. There is no correspondance with high-level source code so it does not make sense to ask about line numbers. In reality, the compiler will mangle your code beyond all recognition before the GC runs.
AFAIK, Java uses the Mark-And-Sweep algorithm. The GC runs in a separate thread over the heap repeatedly.
If a certain reference variable(or object) goes out of scope, its marked for deletion and sweeped off when appropriate(or overwritten).
Also whenever the variable is set to null, that is when the reference count object becomes unreachable by static references and other threads, that is when its reference no longer exists, its marked for deletion again.
Line7 in your code is where it will be marked for deletion.

Which object will be garbage collected?

I wish to confirm which scenario will cause a Garbage Collection on the object myObj:
Scenario 1
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
}
Scenario 2
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
myObj=null;
}
Does explicitly setting an object as null improves garbage collection behavior or will be it same when I reset the object using the new constructor ?
You don't specify the scope of myObj and its important. If its a local variable it almost certainly doesn't matter. If its an instance variable then that could be a long-lived and unnecessary reference in which case setting to null will be useful.
Update: given the updated information that myObj is local to the method, it will be of zero value to set it to null at the end of each iteration of the loop. Consider this example:
public void process(String text) {
String[] lines = text.split("\n");
List<MyObject> list = new ArrayList<MyObject>();
Object myObj;
for (String line : lines) {
myObj = new MyObject(line);
list.add(myObj);
// 1. set myObj = null here
}
list = null; // 2
// 3. do some other stuff
}
public class MyObject {
private final String line;
public MyObject(String line) {
this.line = line;
}
}
Now in this example, let's say that at step 3, it took a long time. Say 10 minutes. During that 10 minutes myObj is pointing to the last line processed. Doesn't sound like a problem? Well it could be. The way substrings work in Java is that they reference the original string. So if you do:
String s = ... // 100 megabytes
String s2 = s.substring(100, 101);
you're actually keeping the entire 100MB in memory because s2 references s.
So in the function I have above, myObj references a line which references the entire file. Changing step 1 to myObj = null; would actually help that because this reference is preventing the object being garbage collected.
Note: step 2 is important here because if you didn't nullify the list all the references would exist anyway.
You just need to think about how references work. An object won't be garbage collected while a reference to it exists. This means clearing long-lived references and keeping variables scoped as tightly as possible. The correct solution for the above is:
for (String line : lines) {
Object myObj = new MyObject(line);
...
}
and then myObj is scoped inside the loop so as soon as the loop ends or another iteration begins it has gone out of scope, which is much better.
Setting it to null will have no effect, since the object is still reachable via arList.
That is, your MyObect instances will live at least as long as arList.
EDIT: Based on your comment, it does sound like myObj is longer-lived. In that case, set it to null after the end of your loop.
I think that this is the root of your misunderstanding.
hmm.. but I don't wish to keep 2 copies of myObj , one in arList and one in the original variable. How can I flush myObj once I add it to arLsit ?
You do NOT "keep two copies of myObj". In your examples, there is only ever one "copy" of each MyObject instance created by the loop. The sequence is:
You create a MyObject instance, assigning its reference to myObj.
You add the reference to the instance to the ArrayList that arList refers to.
You assign null to the reference in myObj.
Note that adding the reference to the list does NOT create a copy of the MyObject instance. It simply means that that you have the reference in two places instead of
one. And when you assign the null you once again have the reference in just one place.
The other thing to note is that assigning null to something will never CAUSE the garbage collector to run. All it does is to (explicitly) remove a potential copy of a reference from consideration the next time the garbage collector is run.
Finally, if we assume that the scoping is as follows, then the line C will have no discernible effect ... unless either line A or line B triggers a garbage collection.
{
MyObject myObj;
ArrayList arList = new ArrayList();
while (someCondition) { // A
myObj = new MyObect(); // B
arList.add(myObj);
myObj = null; // C
}
}
Because it is in a while, myObj is always overwritten (the reference). So in Scenario 1 only one object (the last added in arList) will not be null.
It would be better if you declare it in the while statement:
while(someCondition)
{
MyObect myObj = new MyObect(); // a custom object
arList.add(myObj);
}

Categories

Resources