Garbage collection when application ends - java

As far as I know objects are available to be garbage collected when assigning a null value to the variable :
Object a = new Object;
a = null; //it is now available for garbage collection
or when the object is out of scope due to the method's execution is done:
public void gc(){
Object a = new Object;
} //once gc method is done the object where a is referring to will be available for garbage collection
given with the out of scope isn't also the same when the application just ended?
class Ink{}
public class Main {
Ink k = new Ink();
public void getSomething(){
//method codes here
}
public static void main(String[] args) {
Main n = new Main();
}
}
where I expect 2 objects (Ink object and Main object) should be garbage collected when the application ends.

When the Java application terminates, the JVM typically also terminates in the scope of the OS, so GC at that point is moot. All resources have returned to the OS after as orderly a shutdown of the JVM as the app defined.

You are confusing the event of an object becoming eligible for garbage collection with the actual process of collecting garbage or, more precisely, reclaiming memory.
The garbage collector doesn’t run just because a reference became null or an object went out of scope, that would be a waste of resources. It usually runs because either, memory is low or CPU resources are unused.
Also, the term “garbage collection” is misleading. The actual task for the JVM is to mark all objects being still alive (also known as reachable objects). Everything else is considered reclaimable, aka garbage. Since at the termination of the JVM, the entire memory is reclaimed per se, there is no need to search for reachable references.
That said, it’s helpful to understand, that most thinking about the memory management is useless. E.g. in your code:
public void gc(){
Object a = new Object;
// even here the object might get garbage collected as it is unused in subsequent code
}
the optimizer might remove the entire creation of the object, as it has no observable effect. Then, there will no garbage collection, as the object hasn’t been created in the first place.
See also here.

JVM monitors the GC roots - if an object is not available from a GC root, then it is a candidate for garbage collections. GC root can be
local variables
active java threads
static variables
jni references

Related

Does not storing a newly declared object cause a memory leak?

What I mean to say through the post title is - doing this:
public static void makeNewObjectAndDoTask() {
new SomeClass().doYourTask();
}
I have myself written such code in languages such Java and JavaScript - declaring a new object without storing it in a variable, JUST to call one of its methods. Does this cause memory leaks? ..or does the object get cleared at the end of the method-stack / gets freed by the Java Garbage Collector?
Should I just be doing this instead - for safety?:
public static void makeNewObjectAndDoTask() {
SomeClass obj = new SomeClass().doYourTask();
obj = null;
//System.gc(); // Perhaps also call the collector manually?
}
As the commentors already answered, there is no memory leak in code like
public static void makeNewObjectAndDoTask() {
new SomeClass().doYourTask();
}
at least in itself, assuming that the SomeClass() constructor and the doYourTask() methods don't create memory leaks.
Definitely, the garbage collector will clean up the SomeClass instance at some time in the future.
How does it work?
Instances that are no longer accessible from program code will be garbage collected. Accessibility means being referenced in a variable, field, array element, method argument and so on.
As soon as the new SomeClass().doYourTask(); statement has finished, there is no way to access this individual SomeClass instance any more. So, it fulfills the garbage collection criteria.
The next time the garbage collector runs, it can reclaim the memory occupied by the instance (and its fields, recursively, as long as they aren't referenced elsewhere).
The alternative code
public static void makeNewObjectAndDoTask() {
SomeClass obj = new SomeClass().doYourTask();
obj = null;
}
only delays the garbage collection opportunity, as it stores a reference in obj, thus making the instance accessible for at least a tiny additional period of time, until you assign obj = null;.
Manually calling the garbage collector as in System.gc(); rarely is a good idea. It forces the GC to run (and to spend execution time on cleaning up memory), instead of relying on the JVM's highly optimized GC scheduling strategies. Don't do it unless you have a thorough understanding of the garbage collector, which led you to the conclusion that the GC strategy fails in your case.
We don't want OutOfMemoryErrors, and we don't want excessive time wasted for garbage collection, and the standard GC system does a very good job in both aspects.

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.

Garbage Collection (Local references)

I have confusions on how GC works in Java.
Below is the code snippet that confuse me:
private Data data = new Data();
void main() {
for (int i = 0; i < 100 ; i++) {
MyThread thread = new MyThread(data);
thread.start();
}
System.gc();
// Long running process
}
class MyThread extends Thread {
private Data dataReference;
MyThread(Data data) {
dataReference = data;
}
}
In the above example if gc is called before continuing further (// Long running process)
will the local threads will be garbage collected?
Or GC will mark them (MyThread local references) as alive since it holds the reference to global reference data?
The MyThread instances may be garbage collected only after they are done (i.e. their run method is done). After the for loop ends, any instances of MyThread whose run method is done may be garbage collected (since there are no references to them).
The fact the the MyThread instances each hold a reference to a Data instance that doesn't get garbage collected doesn't affect the time the MyThread instances become eligible for garbage collection.
Your MyThread instances will not be eligible for garbage collection until they have finished running.
The thread stack and local variables for any live (i.e. started but not terminated) thread are reachable by definition.
A reachable object is any object that can be accessed in any potential continuing computation from any live thread. (JLS 12.6.1)
Furthermore, since a live thread could call Thread.currentThread(), the thread's Thread object must also be reachable as long as the thread is live ... irrespective of any other references to it.
However, if the reference to a Thread object becomes unreachable before the start() method has been called, it will be eligible for garbage collection. If this was not so, creating and not starting a Thread would be a memory leak!
You can always call to the garbage collection and but it is not guaranteed to run at the same time. (may or may not depending on your system). because garbage collection running under the daemon thread which is a low priority thread.
An object becomes eligible for Garbage collection or GC if it's not reachable from any live threads or by any static references. In other words, you can say that an object becomes eligible for garbage collection if its all references are null. Cyclic dependencies are not counted as the reference so if object A has a reference to object B and object B has a reference to Object A and they don't have any other live reference then both Objects A and B will be eligible for Garbage collection.
garbage-collection-in-java
There is no grantee that a gc will be executed after a System.gc(); call. A System.gc() call simply SUGGESTS that the VM do a garbage collection.
And thread is not the target for a gc. A thread won't be cleaned up unless its finished running.
Generally speaking, objects are juedged to be alive, if they are still referenced by others.
You should never be calling System.gc. The system will call it for you when low on memory.
In Java, GC works on a system called Mark and Sweep. The algorithm works like this
Start with a set of root objects (GC roots) and a set of all the objects allocated.
Mark those roots
Mark every object reachable from those roots, by visiting every field of these objects recursively.
When every possible object is marked, walk the list of all objects. If an item is not marked, free it.
(This is a simplification, the modern implementation works sort of like this, but is far more sophisticated).
So what is a GC root? Any object stored in a local variable still in scope, in a static variable, in a JNI reference, and all threads that are currently running.
So no, a thread won't be cleaned up unless its finished running. That's why threads so easily create a memory leak- as long as they run, any object they have a reference to cannot be freed because a GC root (the thread) has a reference to it.
But the relationship always goes down from the root to other objects. If Foo holds a reference to Bar, Foo can be deleted regardless of if Bar can be. But if Foo can't be deleted, then neither can Bar.

What does "finalize objects on finalization queue" do? [duplicate]

My understanding of finalization is this:
To clean up or reclaim the memory that an object occupies, the Garbage collector comes into action. (automatically is invoked?)
The garbage collector then dereferences the object. Sometimes, there is no way for the garbage collector to access the object. Then finalize is invoked to do a final clean up processing after which the garbage collector can be invoked.
Is this an accurate description of finalization?
The garbage collector is working automatically in the background (although it can be explicitly invoked, but the need for this should be rare). It basically cleans up only objects which are not referenced by other objects (granted, the full picture is more complicated, but this is the basic idea). So it does not change any references in any live objects. If an object can not be accessed from any live object, this means that it can be safely garbage collected.
Finalization was meant to clean up resources acquired by the object (not memory, but other resources, e.g. file handles, ports, DB connections etc.). However, it did not really work out :-(
it is unpredictable when finalize() will be called
in fact, there is no guarantee that finalize() will be called ever!
So even if it were guaranteed to be called, it would not be a good place to release resources: by the time it is called to free up all the DB connections you have opened, the system may have run out of free connections completely, and your app does not work anymore.
From this article:
Any instances of classes that
implement the finalize() method are
often called finalizable objects. They
will not be immediately reclaimed by
the Java garbage collector when they
are no longer referenced. Instead, the
Java garbage collector appends the
objects to a special queue for the
finalization process. Usually it's
performed by a special thread called a
"Reference Handler" on some Java
Virtual Machines. During this
finalization process, the "Finalizer"
thread will execute each finalize()
method of the objects. Only after
successful completion of the
finalize() method will an object be
handed over for Java garbage
collection to get its space reclaimed
by "future" garbage collection.
You are free to do virtually anything
in the finalize() method of your
class. When you do that, please do not
expect the memory space occupied by
each and every object to be reclaimed
by the Java garbage collector when the
object is no longer referenced or no
longer needed. Why? It is not
guaranteed that the finalize() method
will complete the execution in timely
manner. Worst case, it may not be even
invoked even when there are no more
references to the object. That means
it's not guaranteed that any objects
that have a finalize() method are
garbage collected.
Also, this article from Sun has some nice diagrams explaining the process.
Nope. The finalize() method is run only if the garbage collector attempts to reclaim your object.
Any memory used by your object will (usually, I can't think of an exception) automatically be connected to your object and cleaned up along with it. Finalization, therefore, isn't meant for freeing memory, but rather any other resources your object may be associated with. For example, this could be used to close open files or database connections, or perhaps run some low-level code interfacing with the operating system to release some system-level resources.
Actually, here's the behavior of the finalize() method:
Once the Garbage collector runs (the VM decides it needs to free up memory, you cannot force it to run) and decided to collect the memory from this object (which means there are NO references pointing to it anymore, from reachable objects at least), just before it deletes the memory occupied by it, it runs the method finalize() on the object. You can be sure that if garbage collected, the object will run finalize() just before it disappears, but you cannot be sure that it will get GC'ed at all so you shouldn't rely on the method to do any sanitizing at all. You should run sanitizing statements inside finally {} blocks and not use finalize() as it is not guaranteed to run.
Furthermore, some people have done performance tests and showed that the finalize method somewhat slows down creation/destruction of the object. I cannot remember the source so treat this info as not very reliable. :)
Finalization is used to clean up resources, which cannot be freed by the garbage collector. For example, consider a program which allocates (via some native API) resources directly from the OS. This usually yields some kind of "handle" (a UNIX file descriptor or Windows HANDLE, or something similar):
class Wrapper {
private long handle;
private Handle(long h) {
handle = h;
}
private static native long getHandleFromOS();
static Wrapper allocate() {
return new Handle(getHandleFromOS());
}
}
So, what happens, if your code allocates an instance of class Wrapper? Well the class allocates some kind of OS specific resource and keeps a reference to it (the handle) in a member variable. But what happens, when the last Java reference to a wrapper instance is lost? Now, the garbage collector will (at some point) reclaim the space of the now defunct wrapper instance. But what happens to the OS resource allocated by the wrapper? It will be leaked in the above scenario, which is a bad thing, if it is a costly resource, such as a file descriptor.
In order to allow your code to clean up in such a scenario, there is the finalize method.
class Wrapper {
private long handle;
private Handle(long h) {
handle = h;
}
protected void finalize() {
returnHandleToOS(handle);
}
private static native long getHandleFromOS();
private static native void returnHandleToOS(long handle);
static Wrapper allocate() {
return new Handle(getHandleFromOS());
}
}
Now, when the GC reclaims the space of a wrapper instance, the finalizer makes sure, that the resource is properly returned to the OS.
This sounds all nice, but as others have already pointed out, the downside is, that finalization is inherently unreliable: you do not know when the finalizer will be run. Worse: there are no guarantees that it will be run at all. So ist best to provide an dispose mechanism and use finalization only as safety-net in case, the clients of your class forget to properly dispose their references:
class Wrapper {
private long handle;
private Handle(long h) {
handle = h;
}
protected void finalize() {
if( handle != 0 ) returnHandleToOS(handle);
}
public void dispose() {
returnHandleToOS(handle);
handle = 0;
}
private static native long getHandleFromOS();
private static native void returnHandleToOS(long handle);
static Wrapper allocate() {
return new Handle(getHandleFromOS());
}
}

Garbage collection of local variables inside a static function

I have written below ETL function in Java which is invoked with 1000-2000 events every minute and returns the events which have been loaded successfully (for some check-pointing purpose):
public static Event[] loadEvents(Event[] events) {
List<ITuple> persistedEvents = new ArrayList<Event>();
List<DestinationMessage> destinationMessages = convertToDestinationFormat(events);
loader.send(destinationMessages); // Synchronous persistence call
for (Event event : events) {
persistedEvents.add(event);
}
return persistedEvents.toArray(new Event[persistedEvents.size()]);
}
private static List<DestinationMessage> convertTuplesToKafkaMessages(Event[] events) {
List<DestinationMessage> destinationMessages = new ArrayList<DestinationMessage>();
for (Event event : events) {
DestinationMessage destinationMessage = new DestinationMessage();
destinationMessage.setData(event.getData());
destinationMessages.add(destinationMessage);
}
return destinationMessages;
}
If the functions where non-static I am sure there is no memory leak, but I want to understand if it makes any difference in case functions are static as above?
I believe it should not as the objects are instantiated inside the function call so they should get garbage collected every time the function call gets over (and depending on when garbage collector actually does it).
I am facing heap space issue on my machine and just wondering if this function could be the culprit. Memory usage keeps on increasing from 6GB to 16GB (available memory).
Could someone please point out memory leak, if any. Do I need to set destinationMessages to NULL at the end of loadEvents?
Static fields are associated with the class, not an individual instance.
Static fields are cleaned up when the ClassLoader which hold the class unloaded. In many simple programs, that is never.
If you want the fields to be associated with an instances and cleaned up then the instance is cleaned up, make them instance fields, not static ones.
You don't have your facts quite right in terms of garbage collection
In Java (or C, or C++) there are functionally 3 kinds of memory: System mem (ignore), stack and heap. Stack memory is automatically cleared when a function returns. The only memory that needs to be collected is memory that's allocated in the heap, and this only happens when garbage collection (gc) runs.
This has nothing to do with static / non-static context.
If you are having memory issues, you might want to create a counter that counts how many times your method has been called, and explicitly call System.gc(); after a set number of runs

Categories