How do final fields NOT leak memory? - java

I have been, without a question, using the final keyword for years to denote fields that should not change for the lifetime of an instance/class. Suddenly this occured to me...
So given this example:
public class TestFinalGC{
private TestFinalGC(){}
private final Object obj = new Object();
public static void main(String []args){
TestFinalGC instance = new TestFinalGC();
// instance Ref -> actual instance ->? obj ref-> actual obj
System.out.println(instance.obj);
instance = null;
//say GC makes sweep here... what happens?
//lets assume theres more code, obj would obviously be eligible for GC on app exit.
}
}
How does the obj member NOT leak here? Are final fields automatically WeakReferences such that if the strong references to parent(s) are nulled, they are eligible for garbage collection?
The JLS does not seem to note anything special about final
Update:
So this question of mine was founded on the premise that "reachability" and strong/weak references are closely related. There is this confusing oracle doc on reachability that leads me to believe that nested references should always be "strongly reachable". Hence, I do null my nested object references in all my objects, but it appears that this obviously should not be the case from all of the comments I am receiving.
So regarding "reachability", then, is it simply just that nested object references are no longer considered "reachable" if parent references are no longer reachable?
It could be is true that the premise of this problem is incorrect, but there is still intriguing information to consolidate here.

As Makoto suggested, there is simply nothing special about final in variable declarations as far as GC is concerned. In your example code
private final Object obj = new Object();
will be garbage collected at the same time as
private Object obj = new Object();
Both are strong references, but are invalidated and garbage collected together with their parent class TestFinalGC instance. That is because when the instance is GC'd, the reference fields are destroyed as well and the references do not exist any more. obj's reference count thus decreases by one.
However, should you write something like
Object x = myTestFinalGC.obj; // only works if your obj is not private, of course
Then the object will not be garbage collected because it will still have one reference lingering around (assuming this particular line of code is in another class instance that remains alive when myTestFinalGC is garbage collected.
tl;dr: memory allocations are garbage collected when their hard reference count drops to zero (and the collector runs, of course). final doesn't change this fact.

Related

Weakly referenced object won't get garbage collected

My concern is about an instance of an object that was once strongly referenced, but after an explicit null assignment to its strong reference and after an explicit System.gc() call, the instance is still reachable via the weak reference. If I understand correctly, when a referred object has only weak references left, the referent is guaranteed to be cleared in the next GC session. What am I missing?
Reference code:
public class References {
public static void main(String[] args) {
Example strongReferenceWrappedInWeak = new Example(42);
strongReferenceWrappedInWeak.printA();
WeakReference<Example> exampleWeakReference = new WeakReference<>(strongReferenceWrappedInWeak);
System.gc();
Example retrievedExample = exampleWeakReference.get();
retrievedExample.printA(); //this works, because a strong reference is present to the instance, hence it's not cleared
strongReferenceWrappedInWeak = null; //eligible for garbage collection
System.gc();
Example retrievedExampleTwo = exampleWeakReference.get(); //should be null
retrievedExampleTwo.printA(); //should throw NPE
}
}
class Example {
private int a;
Example(int a) {
this.a = a;
}
void printA() {
System.out.println(this.a);
}
}
strongReferenceWrappedInWeak = null does not make the Example object instance eligible for garbage collection, because retrievedExample still maintains a strong reference to it.
To fix, add retrievedExample = null;
Example strongReferenceWrappedInWeak = new Example(42);
strongReferenceWrappedInWeak.printA();
WeakReference<Example> exampleWeakReference = new WeakReference<>(strongReferenceWrappedInWeak);
System.gc();
Example retrievedExample = exampleWeakReference.get();
retrievedExample.printA(); //this works, because a strong reference is present to the instance, hence it's not cleared
retrievedExample = null;
strongReferenceWrappedInWeak = null; //now eligible for garbage collection
System.gc();
Example retrievedExampleTwo = exampleWeakReference.get(); //will be null
retrievedExampleTwo.printA(); //will throw NPE
Alternatively, don't create a strong reference with a local variable, just call the method directly off the weak reference. That way you don't accidentally leave a strong reference behind, as you did. *(During the printA() call, the this reference is a strong reference, so object cannot be GC'd during the call)*
Example strongReferenceWrappedInWeak = new Example(42);
strongReferenceWrappedInWeak.printA();
WeakReference<Example> exampleWeakReference = new WeakReference<>(strongReferenceWrappedInWeak);
System.gc(); //does not collect object, since strong reference still exists
exampleWeakReference.get().printA(); //works
strongReferenceWrappedInWeak = null; //eligible for garbage collection
System.gc(); //collects object, since it is now weakly referenced only
exampleWeakReference.get().printA(); //throws NPE
Output (from both)
42
42
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:**)
Tested on Java 13
Garbage Collection works in mysterious ways.
There have been several implementations of garbage collectors in the Java ecosystem, with very different behaviors.
When garbage collection runs varies by the implementation of the garbage collector, and also may depend on the current condition of the JVM. One collector might run almost continuously, while another might wait until low on memory. (I’m greatly oversimplifying here, to make the point clear.)
Whether all garbage is collected, or just some of it, may also vary by collector implementation and by the state of the JVM.
The call to System.gc is merely a suggestion, not a command. A garbage collector is free to ignore it.
In Java, you should not be making any great effort at managing memory. The modern JVM implementations are far better at that than any single programmer is likely to be. Just be sure to release all references to your objects when done using them. Or use WeakReference/SoftReference. Then trust the JVM and garbage collector to do its job.
In extreme cases (very large memory, or extreme volumes of object churn) you might want to study the behaviors of various garbage collector implementations. And maybe consider alternatives such as Zing from Azul Systems or GraalVM from Oracle. But for most projects, the usual OpenJDK-based JVMs work quite well.

do you need to null objects?

duplicate - How to destroy java objects?
My question is very simple. I am new to app development with Java and am not sure whether I need to null objects after i am finished with them. for example i am using libGDX to create a game and I have several objects (Actors) being created. when I am finished with them do I simply call
obj.remove();
or should i -
obj.remove();
obj = null;
do I save memory by nulling objects or is there no advantage to be had?
No you do not need to null or manually delete objects. The java garbage collector will do this for you for any objects that have no pointers referencing them (when an object goes out of scope for example).
Generally, in java, marking the Object references as null is done to make it explicitly eligible for GC. If an object is unreachable, then it becomes eligible for GC, so, yes, you can mark it as null and let the GC do its work.
The Object will become unreachable only when there is no reference pointing to it.
example :
class MyTest {
#Override
protected void finalize() throws Throwable {
System.out.println("object is unreachable..");
}
}
// In some other class
public static void main(String[] args) {
MyTest o1 = new MyTest();
MyTest o2 = new MyTest();
System.gc();
o1 = null;
System.gc();
System.out.println("hello");
}
O/P:
hello
object is unreachable..
Here, you might have several thousand lines of code after "hello". You might want to make the GC's job easier by marking the object's references as null.
Manually nulling Objects in Java is bad, because it is slowing down most garbage collection (GC) algorithims. The GC detects by itself wether an Object is reachable or not and then it gets removed. After nulling an object the space in memory is still used and only after the GC recycles the space it can be used again. So nulling objects does not free up your space immediately. Also starting the GC manually is a bad idea. It is started by the VM if it is needed.

Can an instance be garbage collected when its member being exposed to outside world

Take the following case
// class Toy {
// public Object b = new Object();
// }
Toy toy = new Toy();
Object theB = toy.b;
toy = null;
// Can toy instance be garbage collected right now?
I thought maybe toy cannot be garbage collected, as theB is currently referring to toy.b, and variable b cannot live without toy (As b is an instance member variable of toy)?
The short answer
Yes, it can, since there are no strong references to the instance of Toy. Think about it: how could you ever refer back to the original Toy instance? Impossible, isn't it? Therefore, it is indeed garbage, and will be collected.
For more information on reachability and types of references in Java (ie, what are strong references, weak references, etc, and how do these kinds of references interact with the Garbage Collector), take a look at the excellent documentation of the package java.lang.ref.
The more complete, things-are-not-so-simple answer
To extend a little bit the discussion, and to be absolutely precise, I can think of at least one situation in which the instance of Toy can never be collected even after your toy = null, were the code of the class Toy different.
If the constructor of the Toy class adds a reference to the newly created instance in some kind of global variable (or, in more precise terms, if the object is strongly reachable from a GC root). For example:
public class Toy {
private static final List<Toy> myToys = new ArrayList<>();
public Toy() { myToyw.add(this); }
}
If this is the case, then when you do toy = null in your code, still the instance cannot be GCed simply because there's still a way to reach it (through strong references), namely Toy.myToys.get(0).
However, this is just for completeness. I strongly advise against this type of code, since it will certainly bring lots of headaches, including, but not limited to, strange memory leaks (ie, the instance cannot be GCed) and problems with multithreading (ie, you published a reference to an instance before its constructor returned, then another thread might see the object as partially initialized, ie, possibly in an inconsistent state).
Yes, toy can be garbage collected if nobody refers to it. Once b is of type Object it refers only to its own Class object and nothing else, so toy is not referred by b.

Is object eligible for garbage collection after "obj = null"?

I know System.gc() is not guaranteed to cause GC, but theoretically, in the following code, will the object obj be eligible for garbage collection?
public class Demo {
public static void main(String[] args) throws Exception {
SomeClass obj = new SomeClass();
ArrayList list = new ArrayList();
list.add(obj);
obj = null;
System.gc();
}
}
class SomeClass {
protected void finalize() {
System.out.println("Called");
}
}
At the point where you call System.gc() the SomeClass instance you created is not eligible for garbage collection because it is still referred to by the list object, i.e. it is still reachable.
However, as soon as this method returns list goes out of scope, so obj will then become eligible for garbage collection (as will list).
Simply setting the reference obj to null does not, by itself, make the object referred to eligible for garbage collection. An object is only eligible if there are no references to it from the graph of visible objects.
will the object obj be eligible for garbage collection?
Only those objects are garbage collected who don't have even one reference to reach them. (except the cyclic connectivity)
In you code, there are two reference that are pointing to new SomeClass();
obj
zeroth index of list
You put obj = null, i.e. it's not pointing to that object anymore. But, still there exists another reference in list which can be used to access that object.
Hence the object will be eligible for GC only when main returns. i.e. you can't see the output of finalize method even if it got called. (not sure if JVM still calls it)
No, because the object actually exists in the list.
You as Java programmer can not force Garbage collection in Java; it will only trigger if JVM thinks it needs a garbage collection based on Java heap size
When a Java program started Java Virtual Machine gets some memory from Operating System. Java Virtual Machine or JVM uses this memory for all its need and part of this memory is call java heap memory.
Heap in Java generally located at bottom of address space and move upwards. whenever we create object using new operator or by any another means object is allocated memory from Heap and When object dies or garbage collected ,memory goes back to Heap space in Java
EDIT :
will the object obj be eligible for garbage collection?
No, because the object is still in the ArrayList.
Agreed, it won't be garbage collected as long as its there in the list.

Does setting Java objects to null do anything anymore?

I was browsing some old books and found a copy of "Practical Java" by Peter Hagger. In the performance section, there is a recommendation to set object references to null when no longer needed.
In Java, does setting object references to null improve performance or garbage collection efficiency? If so, in what cases is this an issue? Container classes? Object composition? Anonymous inner classes?
I see this in code pretty often. Is this now obsolete programming advice or is it still useful?
It depends a bit on when you were thinking of nulling the reference.
If you have an object chain A->B->C, then once A is not reachable, A, B and C will all be eligible for garbage collection (assuming nothing else is referring to either B or C). There's no need, and never has been any need, to explicitly set references A->B or B->C to null, for example.
Apart from that, most of the time the issue doesn't really arise, because in reality you're dealing with objects in collections. You should generally always be thinking of removing objects from lists, maps etc by calling the appropiate remove() method.
The case where there used to be some advice to set references to null was specifically in a long scope where a memory-intensive object ceased to be used partway through the scope. For example:
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; <-- explicitly set to null
doSomethingElse();
}
The rationale here was that because obj is still in scope, then without the explicit nulling of the reference, it does not become garbage collectable until after the doSomethingElse() method completes. And this is the advice that probably no longer holds on modern JVMs: it turns out that the JIT compiler can work out at what point a given local object reference is no longer used.
No, it's not obsolete advice. Dangling references are still a problem, especially if you're, say, implementing an expandable array container (ArrayList or the like) using a pre-allocated array. Elements beyond the "logical" size of the list should be nulled out, or else they won't be freed.
See Effective Java 2nd ed, Item 6: Eliminate Obsolete Object References.
Instance fields, array elements
If there is a reference to an object, it cannot be garbage collected. Especially if that object (and the whole graph behind it) is big, there is only one reference that is stopping garbage collection, and that reference is not really needed anymore, that is an unfortunate situation.
Pathological cases are the object that retains an unnessary instance to the whole XML DOM tree that was used to configure it, the MBean that was not unregistered, or the single reference to an object from an undeployed web application that prevents a whole classloader from being unloaded.
So unless you are sure that the object that holds the reference itself will be garbage collected anyway (or even then), you should null out everything that you no longer need.
Scoped variables:
If you are considering setting a local variable to null before the end of its scope , so that it can be reclaimed by the garbage collector and to mark it as "unusable from now on", you should consider putting it in a more limited scope instead.
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; // <-- explicitly set to null
doSomethingElse();
}
becomes
{
{
BigObject obj = ...
doSomethingWith(obj);
} // <-- obj goes out of scope
doSomethingElse();
}
Long, flat scopes are generally bad for legibility of the code, too. Introducing private methods to break things up just for that purpose is not unheard of, too.
In memory restrictive environments (e.g. cellphones) this can be useful. By setting null, the objetc don't need to wait the variable to get out of scope to be gc'd.
For the everyday programming, however, this shouldn't be the rule, except in special cases like the one Chris Jester-Young cited.
Firstly, It does not mean anything that you are setting a object to null. I explain it below:
List list1 = new ArrayList();
List list2 = list1;
In above code segment we are creating the object reference variable name list1 of ArrayList object that is stored in the memory. So list1 is referring that object and it nothing more than a variable. And in the second line of code we are copying the reference of list1 to list2. So now going back to your question if I do:
list1 = null;
that means list1 is no longer referring any object that is stored in the memory so list2 will also having nothing to refer. So if you check the size of list2:
list2.size(); //it gives you 0
So here the concept of garbage collector arrives which says «you nothing to worry about freeing the memory that is hold by the object, I will do that when I find that it will no longer used in program and JVM will manage me.»
I hope it clear the concept.
One of the reasons to do so is to eliminate obsolete object references.
You can read the text here.

Categories