Can variable of nested static class be garbage collected? - java

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).

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);
}
}

In an interview I was asked how do you detect memory leak in Java?

I do not know how to answer this question. Instead, I told them that I have not see any practical code/situation in a Web Application that could a memory leak. I also told him that if there are too many object being created and these objects going out of scope, the GC will take care of reclaiming the memory.
My questions are
(1) Was my answer good enough ?
(2) Can you please give me a practical example of the Java Memory leak in a Web and/or non-Web environment?
Thanks
Good topic!
You need to monitor Java memory consumption first.
The simplest way to do this is to use jstat utility that comes with every JVM.
jstat -gcutil <process_id> <timeout>
It will report memory consumption for each generation (Young, Eldery and Old) and garbage collection times (Young and Full).
As soon as you spot that Full Garbage Collection is executed too often and takes too much time, you can assume that application is leaking memory.
Then you need to create a memory dump using jmap utility:
jmap -dump:live,format=b,file=heap.bin <process_id>
Then you need to analyse heap.bin file with Memory Analyser, Eclipse Memory Analyzer (MAT) for example.
MAT will analyze the memory and provide you suspect information about memory leaks.
A memory leak, is any situation where you continue to hold on to allocated memory you no longer need and no longer intend to use.
Consider the following example:
public class LeakMemory {
private static final List<String> LEAK = new ArrayList<>();
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("What is your name? ");
while (in.hasNext()) {
name = in.next();
System.out.println("Hi " + name);
LEAK.add(name);
}
}
}
The LEAK list is grows in every iteration, and there's no way to free it up, yet it's never used. This is a leak.
By the normal definition of a memory leak, Java does not have them due to Garbage collection. If we, however, expand the definition a little bit to "Objects the program does not need anymore, but are not garbage-collectible", then there are two scenarios I can think of where such "leaks" could arise.
Scenario 1: record all objects of a class ever created
This example has an artificial taste and is often seen in the context of an exercise. Suppose we want to store every instance of a certain class ever created. This can be achived through a static colleciton:
public class RecordMe {
private static final List<RecordMe> created = new ArrayList<RecordMe>();
...
private final int someValue;
private RecordMe(final int someValue) {
this.someValue = someValue;
}
public static RecordMe of(final int someValue) {
RecordMe me = new RecordMe(someValue);
created.add(me);
return me;
}
public static List<RecordMe> instances() {
return Collections.unmodifiableList(created);
}
}
As soon as an instance of RecordMe is created, it can never be garbage-collected because it will always be referenced through the static list.
The fix would be to check the list before creating a new instance of RecordMe or use List<WeakReference<RecordMe>> (and clean this list from time to time).
Scenario 2: Leaks through inner classes
As we know, a non-staitc inner class holds an implicit reference to the object it was created from. Let's take a look on an extreme example.
public class MemoryTest {
// data has a size of a little over 512 MB.
private final byte[] data = new byte[1024 * 1024 * 512];
private final Field field;
public class Field {
}
public MemoryTest() {
this.field = new Field();
}
public Field getField() {
return this.field;
}
public static void main(String... args) {
MemoryTest test = new MemoryTest();
Field fieldOne = test.getField();
test = null;
test = new MemoryTest();
}
}
If we execute this code with java -Xmx800m MemoryTest, it will throw an OutOfMemoryException. Examples of this sizes are unrealistic in the real, but in smaller sizes and with enough instances, this can also lead to issues. Take, for example, Java's HashMap-implementation. Method keySet() returns an instance of a non-static, inner class. As long as one holds instances to those inner classes, the HashMap cannot be garbage-collected.

How many objects will be eligible for garbage collection?

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.

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);
}
}

Memory usage/ reference in java

I am going to ask a basic question about Java memory usage.
Imagine we have an array List and it is large enough and we don't like to use more memory. Now if I want to pass this array to another methods in this class, or other classes through their constructor or method, do I need additional memory/is there additional memory usage for this array?
If yes, could I just make this array package level, and therefore the other classes in this package could access it directly, without any memory need.
Thank you in advance.
No, no additional memory is necessary. The parameter of a function is passed by copy of the reference. It means that for any kind of object only 4 additional bytes are used.
If you pass an array as parameter and you modify it in the body of the method the changes will be exported outside of method.
Instead if you reassign the array variable, the difference is not visible externally.
This happens because the parameters are passed as copy of the reference and not by reference.
public void vsibleModification(int[] a) {
for (int i = 0; i < a.length; i++) {
// This change is visible outside of method because I change
// the content of a, not the reference
a[i] = a[i] + 1;
}
}
public void nonVisibleModification(int[] a) {
// Non visible modification because a is reassigned to a new value (reference modification)
a = new int[2];
a[0] = 1;
a[1] = 2;
}

Categories

Resources