It is controlled by a thread known as Garbage Collector. Java provides two methods System. gc() and Runtime. gc() that sends request to the JVM for garbage collection.
If your application's object creation rate is very high, then to keep up with it, the garbage collection rate will also be very high. A high garbage collection rate will increase the GC pause time as well. Thus, optimizing the application to create fewer objects is THE EFFECTIVE strategy to reduce long GC pauses.
Common triggers for garbage collection are Eden space being full, not enough free space to allocate an object, external resources like System. gc(), tools like jmap or not enough free space to create an object. Interested in a solution that helps you keep an eye on memory usage?
Hold a reference. If your object is getting collected prematurely, it is a symptom that you have a bug in the design of your application.
The garbage collector collects only objects to which there is no reference in your application. If there is no object that would naturally reference the collected object, ask yourself why it should be kept alive.
One usecase in which you typically have no references, but want to keep an object is a singleton. In this case, you could use a static variable. One possible implementation of a singleton would look like this:
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqInstance;
}
}
Edit: Technically, you can store a reference somewhere in your finalizer. This will prevent the object from being collected until the collector determines again that there are no more references. The finalizer will only be called at most once, however, so you must ensure that your object (including its superclasses) need not be finalized after the first collection. I would advise you, however, not to use this technique in actual programs. (It will leave colleagues like me yelling WTF!? ;)
protected void finalize() throws Throwable {
MyObjectStore.getInstance().store(this);
super.finalize(); // questionable, but you should ensure calling it somewhere.
}
The trick answer your interviewer was looking for is probably that he wants you to know that you can prevent garbage collection from removing an object by forcing a memory leak.
Obviously, if you keep a reference to the object in some long-lived context, it won't be collected, but that's not what the OP's recruiter asked about. That's not something which happens in the finalize method.
What you can do to prevent garbage collection from within the finalize method is to write an infinite loop, in which you call Thread.yield();
(presumably to keep an empty loop from being optimized away):
@Override
protected void finalize() throws Throwable {
while (true) {
Thread.yield();
}
}
My reference here is an article by Elliot Back, in which describes forcing a memory leak by this method.
Just another way in which finalize methods are evil.
The best way is to use Unsafe, although ByteBuffer
might be a possible workaround for some cases.
Also search for the keyword "off-heap" memory.
Unsafe
Advantages over ByteBuffer
:
It is not however easy to get working. The method is described in the following articles:
They all consist of the following steps:
we need a sizeof
operator, which Unsafe does not have. How to make one was asked at: In Java, what is the best way to determine the size of an object?. The best options is likely the instrument
API, but that requires you to create a Jar and use special command line options...
once we have sizeof
, allocate enough memory with Unsafe#allocateMemory
, which is basically a malloc
and returns an address
create a regular on heap object, copy it to the allocated memory with Unsafe#copyMemory
. To do this, you need to the address of the on-heap object, and the size of the object
set an Object
to point to the allocated memory, then cast the Object
to your class.
It does not seem possible to set the address of a variable directly with Unsafe, so we need to wrap the object into an array or wrapper object, and use Unsafe#arrayBaseOffset
or Unsafe#objectFieldOffset
.
once you are done, free the allocated memory with freeMemory
If I ever get this to not segfault I will post an example :-)
ByteBuffer
Advantages over Unsafe:
JLS says:
The contents of direct buffers may reside outside of the normal garbage-collected heap.
Example of usage with primitives:
ByteBuffer bb = ByteBuffer.allocateDirect(8);
bb.putInt(0, 1);
bb.putInt(4, 2);
assert bb.getInt(0) == 1;
assert bb.getInt(4) == 2;
// Bound chekcs are done.
boolean fail = false;
try {
bb.getInt(8);
} catch(IndexOutOfBoundsException e) {
fail = true;
}
assert fail;
Related threads:
If there is still a reference to the object, it won't get garbage collected. If there aren't any references to it, you shouldn't care.
In other words - the garbage collector only collects garbage. Let it do its job.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With