From this post Strong references never be garbage collected, With this understanding I assume if we create a infinite Strong Reference objects in memory then it must throw OutOfMemory error.
However, When I ran below dummy program it never through OutOfMemory error although I have created infinite objects in while loop.
public class Test2 {
public static void main(String[] args) {
while (true) {
Test2 obj = new Test2();
System.out.println(obj);
}
}
}
Please help me understand if strong referenced objects are never garbage collected then how come there is no OOM error.
You don't keep the strong reference to the object. Each time you go through the loop, there's no longer any reference to the object created in the last iteration, and it is eligible for garbage collection.
Objects are not garbage collected if they are reachable from a GC-root-object via strong references. In your example only one Test2-object is reachable from your thread at any time. The strong reference obj is updated each iteration and thus the previous Test2-object is no longer strongly referenced from anywhere and can be garbage collected.
If you want to create an OOM you might add the new objects to a List and keep them there.
Related
I sometimes see the code of this kind in some library APIs and just in someone's code:
class SomeClass {
private WeakReference<SomeObject> objectWeakReference; // initialized elsewhere
public boolean isObjectAttached() {
return objectWeakReference.get() != null;
}
public SomeObject getObject() {
return objectWeakReference.get();
}
}
and
public void checkAndGetWeakReference() {
SomeClass someClass = new SomeClass();
if (someClass.isObjectAttached()) {
someClass.getObject().doSomethingDirectlyOnReturnedObject(); // can the returned reference be null here ?
}
}
And I'm always worried if there could be NullPointerException once in a blue moon, assuming there are no strong reference to the underlying object at this point.
I don't really know when exactly Garbage Collector can start deleting objects from memory and how does it correlate with the basic thread flow.
It would be nice if someone can shed the light on this particular subject and/or provide some information about the topic.
P.S. I would personally get reference only once and assign it to strong reference. The point of the question is to get some proof the code above is wrong.
The whole point of the WeakReference (and SoftReference as well) is that the referred object may be gc'd at any time no strong reference to the object exists.
Since there exists no strong reference when isObjectAttached() returns, yes it can be garbage collected before it actually gets to execute getObject(). The whole idom is faulty for this use case.
The only safe way is to first get the reference (e.g. to a local variable) and then check it against null. The object can then not be garbage collected in that case, because a local variable is a strong reference.
As per java doc. You should not rely on Garbage collector. Its not sure when it will be executed. Though you are trying explicitly System.gc()
Its always been a lowest priority for JVM for garbage collector. When JVM is free or when your program is around to ran out of memory it can execute GC.
In other case when your program will exit. It will be garbage collected before it is flushed out of JVM memory.
Please refer javadoc for detailed explanation for GC.
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
I would like to add something to all answers.
Your object can be null when you call below method :
public SomeObject getObject() {
return objectWeakReference.get();
}
about garbage collection of this object.
If you do something like below :
public static void main(String args[]) {
SomeClass oSomeClass = new SomeClass();
// this one is strong reference "obj"
// this object can be null. Best practice is to null check before you use it.
// Or i will suggest to call isObjectAttached() method before you use it
Object obj = oSomeClass.getObject();
}
When you do obj = null; somewhere in code after above statement.
This object memory is available for garbage collection. Whenever JVM feels to clean memory. Yes it can collect this object.
Regarding proof of code you are asking.
public boolean isObjectAttached() {
return objectWeakReference.get() != null;
}
This method is made for you to check whether this object is present in memory or it has a valid reference for you.
If it returns true you will never get nullpointer exception.
but if you are not using this method i will suggest to use null check always before you use your object.
Hope I am on right direction and making some sense in my answer. Please respond accordingly.
We all are here to learn ;-)
Enjoy Java, OOP concepts.
Garbage collector internally has its heuristics to collect soft/weak/phantom references. It will not collect those objects in subsequent GC calls. It tracks these objects until it reaches the threshold of that heuristics, GC is not allowed to collect these references.
I have this piece of code, and I am confused about when the Object o becomes eligible for garbage collection in Java.
public class JustSo
{
public static void main(String[] args)
{
for(int i=0;i<4;i++)
{
Object o=new Object();
//o.doSomething();
}
System.out.println("DONE");
}
}
Since it is inside a loop(or any block for that matter), it will become eligible at the end of the loop right?
But I found an answer on a reliable developer site(Don't want to disclose where) that says the earliest the object becomes eligible is at the print statement.
Please clarify.
When it becomes out of scope, so after each iteration of the for loop. An object is eligible for garbage collection when it is no longer reachable, this occurs in 2 situations.
The object no longer has any references point to it.
All references to the object have gone out of scope.
The latter is the situation for the object in question, and it the object's reference is out of scope after the for loop. Prior to the print statement.
As the oracle documentation about the garbagecollector says:
Automatic garbage collection is the process of looking at heap memory, identifying which objects are in use and which are not, and deleting the unused objects. An in use object, or a referenced object, means that some part of your program still maintains a pointer to that object. An unused object, or unreferenced object, is no longer referenced by any part of your program. So the memory used by an unreferenced object can be reclaimed.
This means as soon as an Object isn't referenced from any other Object or is out of scope, it will be marked for deletion. In this case, the reference is out of scope, each time the loop starts again (just before every increment). Thus each object will be marked for deletion at the end of the loop (before the next loop-repetition).
Since you are not saving the reference into some outer-scope variable,and creating new instance each time as soon as single iteration complete, its eligible for garbage collection.
So when you came out of loop, all the objects created inside eligible for GC.
May be you confused with author wording here. Consider below code
for(int i=0;i<4;i++)
{
Object o=new Object();
//o.doSomething();
} -----> objects ready for GC here.
// some other code
// some other code
System.out.println("DONE");
Each time around the loop, around the time when i++ happens, the object will become eligible for GC.
In some library found on google code I came across this util method:
public static void gc(){
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get()!=null)
System.gc();
}
Its doc says it provides a reliable way to call GC, because calling System#gc() is just a hint without any guarantees. I showed it my senior, and he said I should think about why this method is invalid.
I read some articles on weak references but I'm still confused.
Can somebody show me the point?
I have direct experience with the supposed "safe GC" idiom you have posted.
It doesn't work.
The reason is quite simple: just the fact that a weak ref is cleared is not a signal that the object has been collected; it only means that it has become unreachable through any strong or soft reference. In my experience this signal arrives before the object is reclaimed.
A better attempt would be to use a Phantom reference, which at least ensures that the object has entered the finalizable state, but once again, it can still be occupying the heap, and in practice it still is occupying it. Another explanation could be that this particular object, obviously residing in Eden space, did get reclaimed, but the GC run which did it was not exhaustive and there is more memory to reclaim in other generations.
On the other hand, I have very reliably used this trivial idiom:
for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(500); }
Try it and see if it works for you. The sleep part is optional: it is needed only if System.gc() uses concurrent sweeping.
If you object to the apparent fickleness of this approach, just remember that any approach to explicit GC-ing is fickle. This one is at least honest about it—and just happens to work on actual systems. It is, naturally, non-portable and can cease to work at any time for a large array of reasons. Even so, it is the best you'll ever get.
The point is, that System.gc() does not need to clean up all weak references. And consider some Java virtual machines too. If System.gc for once (the first time) does decide to not clean that reference, it is very likely to the next call. Hence you have a possibly infinite loop. Probably depending on other threads changing the state for the garbage collection to terminate the loop.
So: once is enough.
There is no way to guarantee a GC call because just as the documentation says System.gc is just a hint that can be ignored by the system.
So assume that the JVM ignores System.gc - in that case the whole thing just loops until some other part of the systems causes a GC. If you run single-threaded or nobody else allocates much memory you basically create an inifite loop here.
The point is that your thread will stop and wait until the weak reference is cleared, thus "simulating" garbage collection. There's no guarantee when (or indeed even IF) this will actually happen.
You could be stuck waiting on this while for a long, long time.
Programmatic we need to ensure that, when a obj is removed then its corresponding entry should be removed. Only then, that object becomes a candidate for garbage collection. Otherwise, even though it is not used at run-time, this stale object will not be garbage collected.
The object to which this reference refers, or null if this reference object has been cleared.
As your object reference of WeakReference class. so it will not give null. but after removing gc., it provide null.
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
if(ref.get()!=null)
{
System.gc();
System.out.println("remove ref");
}
if(ref.get()!=null){
System.out.println("not execute");
}
Output:
remove ref
Don't assign null value to obj.
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
if(ref.get()!=null)
{
System.gc();
System.out.println("remove ref");
}
if(ref.get()!=null){
System.out.println("execute");
}
Output:
remove ref
execute
Code that tries to force GC is usually a sign for an underlying bigger problem (i.e. design issue or missing knowledge on the developers part).
I have seen a few use cases where calling System.gc() in production code actually makes sense, for example, before printing the current memory usage - it doesn't matter if the values are off but we'd like to improve chances the values are as small as possible. Of course, we knew that GC was enabled - we used this to automatically detect memory leaks on a QA system.
In general, calling System.gc() yells "my code is buggy and I don't know how to fix it!".
When does the object of type list, occupying memory, become eligible for garbage collection, Also where is the variable that holds reference to the list ? In the case of code below, there was no variable assigned to it.
CASE 1:
for (Integer i : returnList()) {
System.out.println(i);
}
In case of a code like:
CASE 2:
List list = returnList();
for (Integer i : list) {
System.out.println(i);
}
list = null;
We can take control of GC, Is there any ways to take care of that in the first case when no variable was assigned ?
To summarize:
What is the mechanism of referrence, without a reference variable to list is case 1?
Does list get eligible for GC'd when stack frame is popped ?
Any way to speed up the eligibility for GC'ing ?
What is the mechanism of referrence, without a reference variable to list is case 1?
There is an implicit reference to the list. This can be seen by understanding that enhanced for like that is translated into:
for(Iterator e = returnList().iterator(); e.hasNext(); ) {
Integer i = (Integer)e.Next();
System.out.println(i);
}
Here, e has a reference to an iterator on returnList, which itself has a reference to returnList. Thus, returnList is rooted as long as e is rooted which is only true while control is in the for loop. When control leaves the for body, e is eligible for collection, so returnList is eligible for collection.
Of course, all of this is assuming that
The owner of returnList isn't maintaining a reference to its return value.
The same list hasn't been returned to another caller and that other caller isn't maintaining a reference to the same list.
Does list get GC'd when stack frame is popped ?
Not necessarily. It will be eligible for collection when the JVM can determine that the referrent has no rooted references to it. Note that it does not necessarily immediately get collected.
Any way to speed up GC in case 1.
It can't be collected any sooner than control leaving the for loop. It might be collected after control leaves the for loop. Let the JVM worry about this.
Note that you can attempt a manual garbage collection via
System.gc();
but note that this might exhibit worse behavior because if it triggers a garbage collection, it might be a full garbage collection. Note that the JVM can ignore this request. You might be wasting a lot of CPU cycles here. Note that on a system with infinite memory, the garbage collector never needs to run. On such a system, requesting the garbage collector could be a complete waste of CPU cycles if the garbage collector obeys your request.
Let the JVM manage the garbage collections. The algorithms for it are highly tuned.
From SCJP page 256-257
The garbage collector does some magical, unknown operations, and when
it discovers an object that can't be reached by any live thread,it
will consider that object as eligible for deletion, and it might even
delete it at some point. (You guessed it; it also might not ever
delete it.) When we talk about reaching an object, we're really
talking about having a reachable reference variable that refers to the
object in question. If our Java program has a reference variable that
refers to an object, and that reference variable is available to a
live thread, then that object is considered reachable.
Setting an object to NULL might help to fasten when the GC deletes the object but it might as well not, you don't have control over that. The JVM will run GC when it senses that memory is running low and you can manually ask it to do so but nothing is guaranteed.
What is the mechanism of reference, without a reference variable to
list is case 1?
see next answer.
Does list get GC'd when stack frame is popped ?
The list is created on the heap - but if the only reference to it was on the stack it is eligible to be collected by GC. That doesn't mean that it'll happen any time soon though.
Any way to speed up GC in case 1.
You can't "speed up" GC, even by calling System.gc(); you're only "suggesting" that the GC can to do its work - again, it won't necessarily happen any time soon.
There's a lot of sense behind it too: say that your program has 2GB of memory to use and is currently using only 2KB - it does not justify GC stopping your program from running and clean the memory only because some objects are eligible for deletion.
You cannot take control of GC.It is managed by JVM. What you can manage is what objects should be available for garbage collection. Although , you can find out when garbage collector will run using finalize method. It is always called before an object is deleted
public class Demo{
static void create()
{
Demo o = new Demo();
}
public void finalize()
{
System.out.println("GC called");
}
public static void main (String ...ar)
{
for (long i=1;i<900000;i++) //Try changing values here
{
create();
}
}
}
Objects created inside the methods are available for GC when method is returned(just like local variables exist for duration of method).However if the method returns an object, it will not be avialble for garbage collection
public class Demo{
public void getDate()
{
Date o = new Date();
StringBuffer d = new StringBuffer(o.toString());
System.out.println(d);
return o;
}
public static void main (String ...ar)
{
Date x= getDate();
}
}
In the above code, object d is available for GC when the method returns. But object o will not be available for collection
I heard most elegant property of java is Garbage Collection
I wanna know does it guarantee that a program will not run out of memory?
No, it's always possible that you'll try to allocate more memory than is available.
Automatic garbage collection only means that garbage (i.e., unreferenced memory) is automatically collected (i.e., reclaimed for further use). If you keep references to it, it's not garbage, and not collected.
No it does not guarantee this. It is perfectly possible for a programmer to mistakingly create objects which never go out of scope, thus consuming more and more memory until all heap is exhausted.
It is the programmer's responsibility to ensure that objects no longer in use are no longer referenced by the application. That way the garbage collector can do its job and reclaim memory used by these objects.
Example
public class Main {
public static void main(String[] main) {
List<String> l = new LinkedList<String>();
// Enter infinite loop which will add a String to
// the list: l on each iteration.
do {
l.add(new String("Hello, World"));
} while(true);
}
}
No, there are still many ways to run out of memory. The garbage collector can only reclaim memory for objects that are no longer referenced - it is up to you to make sure that you are not referencing objects you don't need, or to use Soft References for objects you would like to have, but don't mind disappearing if memory gets tight.
To answer your question, NO. Garbage collection does not guarantee that a program will not run out of memory.
Consider object you don't want to
use any more are like garbage.
References to those objects will be
like having that garbage in your
house.
Garbage collection is like your
town's garbage truck that collects
garbage.
If you won't release those
references, it is like not taking
garbage out and soon your house will
be over filled with garbage as
garbage truck guys won't take out
garbage from your house.
Unreferenced objects will be garbage collected automatically by garbage collector. In java, most references to objects are released automatically once you come out of method.
Objects have reference to other objects, which in turn referr to other objects creating whole object graph. So as such object can be referenced by more than one object.
If object is having zero references,
it is eligible for garbage
collection.
Objects are allocated on heap.
Garbage collector runs from time to
time to delete unreferenced objects
from heap.
If you keep creating more objects on
heap without releasing you will
eventually get OutOfMemoryError
Example with garbage collection at work
public class TestGarbageNoError {
public static void main(String[] args) {
String hugeString;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
System.out.println("i = " + i);
hugeString = getHugeString();
// At each iteration reference variable hugeString
// points to new String object. Hence there will be
// zero reference to previous string object and will
// eventually be garbage collected
}
}
public static String getHugeString() {
StringBuilder sb = new StringBuilder();
for (int x = 0; x < 5000000; x++) {
sb.append(x);
}
return sb.toString();
}
}
.
Example with memory leak at work
public class TestGarbageError {
public static void main(String[] args) {
Collection<String> memoryLeak = new ArrayList<String>();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
System.out.println("i = " + i);
String hugeString = getHugeString();
memoryLeak.add(hugeString);
// At each iteration reference variable hugeString
// points to new String object. But all objects are added
// to memoryLeak Collection and will always have atleast one
// reference, i.e. from memoryLeak object. Hence this string
// objects will never be garbage collected and program will
// eventually run out of memory
}
}
public static String getHugeString() {
StringBuilder sb = new StringBuilder();
for (int x = 0; x < 5000000; x++) {
sb.append(x);
}
return sb.toString();
}
}
No. If you construct a lot of objects (millions) and keep a reference to them so they don't go out of scope (for example by adding them to an ArrayList), you could run out of addressable memory.
Absolutely not. Even in a garbage collected language like Java you can easily lose references, meaning objects will never get garbage collected.
Even then, you may simply instantiate (and keep reference to) too many objects for the system to handle.
How could anything ensure a program doesn't run out of memory short of arbitrarily deleting an item from memory to make room for new allocations?
Now, what if you are actually keeping a reference on (using) the thing randomly chosen to be evicted? You will soon have incorrect behavior.
No. The garbage collector, helps you to free unused memory automatically.
The way it works is, if an object reference can't be reached, the memory for that object may be garbage collected.
For instance:
public void test() {
Object o = new Object();
// the memory used by o may be garbage collected after this line
}
But if you never release object references, the garbage collector will never collect anything and a OutOfMemoryError will be thrown.
List list = ....
public void test() {
o = new Object();
list.add( o );
// the memory used by o WON'T be garbage collected after this line
// because its reference is used in the list.
}
If you use this several times:
while( true ) {
test();
}
The list will keep growing indefinitely until you run out of memory
No. Garbage collection only protects against one kind of memory leak. Specifically, the kind that occurs if you don't explicitly free up memory when your application no longer needs it. If your application holds references to unneeded objects (eg. evergrowing Lists), the garbage collector cannot clean them up and your application can still run out of memory.
No, not at all.
In languages without garbage collection, the programmer (or a library he uses) is responsible for making requests for memory and for returning the allocated memory for "recycling". there are no guarantees that the memory would be available when it is requested. However, if you never explicitly "recycle", there could be a situation where a request is rejected because no memory is available, but that if the memory was recycled that block could have been returned for this request.
Having automated garbage collection means that the system may recycle for you. As a result, certain requests would be filled using "recycled" memory. However, as with non-GC languages, some requests cannot be filled.
For instance, if your system has 1000 blocks available and you need 1500 at the same time, no GC in the world is going to help you because nothing is really available for recycling.
No, garbage collection cannot guarantee that your application will not run out of memory. It will not even guarantee that your application will not run out of memory when memory is available. If you come close to running out of memory or are allocating many object it can cause GC to thrash, throwing an out of memory exception. The program can also run out of memory when it has used all the physical memory (actual and virtual) or the program exceeds the maximum memory allowed by the JVM (see -Xmx).
However, it is guaranteed that before the JVM declares OutofMemoryException it will garbage collect all collectible references and consider to use the now free memory.