Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have the below method.Suppose i call A.m1() 10,000 times from class B.
So all 10,000 MyObj objects will be garbage collected as their scope is only within the m1() method.
There is no memory leak?
class A {
String m1() {
MyObj obj = new Mybj();
}
}
And i call it below
class B {
void m2() {
String s = classAObj.m1();
}
}
The references created in the method are eventually garbage collected when they go out of scope. But it doesn't necessary happen immediately.
Here is a demo that shows that the references are collected. But first
some terms.
hard reference - A normal reference to an object that will be around until it is garbage collected. These are the typical instance values resulting from object creation.
weak references - references that point to the same object as a hard reference. When a hard reference is garbage collected, the associated weak references are also collected.
How this works.
The method m1 is called n times, each time creating a weak reference of an instance of A and returning it.
This is then added to a list.
Once the hard references are garbage collected, the weak references that refer to the same objects will also be collected
The weak reference will then return null when trying to retrieve its associated object.
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class GarbageCollection {
public static void main(String[] args) {
// get out of static context
new GarbageCollection().start();
}
public void start() {
int n = 10_000;
List<WeakReference<A>> weak = new ArrayList<>();
Create n weak references of A by calling m1 and returning the reference.
Then it add to the List.
for (int i = 0; i < n; i++) {
WeakReference<A> wk = m1();
weak.add(wk);
}
Now iterate thru the List of weak references to see how many are null.
Zero is expected since the garbage collector has not yet run. All of those A allocations created in m1 are still lurking around in the heap.
int count = 0;
for (WeakReference<A> wk : weak) {
if (wk.get() == null) {
count++;
}
}
System.out.println(count); // probably zero
Now repeat the same process but explicitly invoke the garbage collector.
count = 0;
System.gc();
for (WeakReference<A> wk : weak) {
if (wk.get() == null) {
count++;
}
}
At this point, count should be non-zero (or possibly n for small values of n) to show some or all of the objects have been collected.
System.out.println(count);
}
public WeakReference<A> m1() {
A a = new A();
return new WeakReference<>(a);
}
}
class A {
}
I think you have a C++ background. In Java, it's quite hard to get a memory leak because of its garbage collection system. Garbage collection can get complicated, but the basic idea is there is a program constantly running in the background looking in the heap for an unused object, and when it finds one, it deletes it. So when you exit the m1() method, there are no references to the new Mybj() object so the garbage collector deletes it.
Related
Please consider the following bit of code :
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static List<String> arraylist=new ArrayList<String>();
//add hello n times to the list
public static void add_to_list(int n)
{
if(n==0)
{
return;
}
else
{
String b=new String("hello");
arraylist.add(b);
add_to_list(n-1);
}
}
public static void main(String args[]) throws IOException
{
add_to_list(5);
for(String s:arraylist)
{
System.out.println(s);
}
}
}
I have tried running this program multiple times and I get the same output as :
hello
hello
hello
hello
hello
My assumptions :
String b goes out of the scope once the method add_to_list is executed
I am referencing the arraylist reference indexes outside their scope
Arraylist contains the reference of the strings created in the method.
Hence my question is :
Is there a possibility that the references are cleaned up by the java collector before I print the value?
Did I just get lucky and the Java collector did not run before I read those values?
your variable arraylist is static, so doesn't go out of scope. It therefore maintains references to its element until the end of the program.
They can't be garbage collected, so you're not "just lucky".
When you create a String using new() operator, it always create a new object in heap memory. In your above code, every time add_to_list() is called it creates a new string object in heap memory and its reference is stored in local variable 'b' which resides in stack memory of add_to_list(). On every call to this method, fresh stack memory is allocated and upon finishing its execution for that particular call, its allocated stack memory is cleared.
But you also adding this string object reference i.e. 'b' to a static ArrayList. Static variables are stored as part of Class object associated with the class and resides in PermGen in Heap memory and will live as long as the class is in memory.
Garbage collection is always working to free memory by clearing any objects without any references. These are objects that are no longer being used. But in your above code all string references are stored in static list and thus they will be garbage collected only when class terminates.
This question already has answers here:
What happens when an object is dereferenced but its member object is still referenced?
(3 answers)
Closed 4 years ago.
Lets say there is this huge object which contains a large number of other huge objects as its attributes, but one attribute is a very small object.
class HugeObject
{
private HugeObject1 x1;
private HugeObject2 x2;
:
:
private HugeObject1000 x1000;
private SmallObject1 s1;
public SmallObject1 getSmallObject()
{
return s1;
}
}
The following code snippet will create a new object based on the small object (SmallObject1). The HugeObject in the runThis() routine goes out of scope, but the SmallObject1 attribute is returned.
public class Test
{
public static void main(String[] args)
{
SmallOjbect1 so = runThis();
//Application continues to run here for a long time.
}
public SmallObject1 runThis()
{
HugeObject ho = new HugeObject();
:
//Do some calculations, call other procedures....
return ho.getSmallObject();
}
}
Is this scenario, is only the SmallObject1 kept in memory or is HugeObject also in memory as SmallObject1 is its attribute.
Even though HugeObject is out of scope, I am not certain if it will remain in memory since one of its attributes are still in memory.
As long as no references to the HugeObject instance remain, it will become eligible for garbage collection. This doesn't mean that it will be garbage collected immediately though (that is up to the JVM).
One thing to watch out for is having (possibly indirect) references from the SmallObject instance back to the HugeObject instance. This could happen, for example, if SmallObject is an inner class of HugeObject. (This article explains the mechanics in some detail.)
If there is a reference chain from the SmallObject instance back to the HugeObject instance, the latter will be kept around for as long as the former exists.
This program can count total number of objects but I am unable to count
the objects destroyed. How this can be done?
package displayobjno;
public class DisplayObjNo
{
public static void main(String[] args)
{
DisplayObject obj1 =new DisplayObject();
DisplayObject obj2 =new DisplayObject();
obj1=null; //How to count the objects being destroyed?
}
}
class DisplayObject
{
static int numOfObj;
DisplayObject()
{
numOfObj+=1;
}
}
You simply cannot do that in Java:
finalization is not guaranteed to run,
garbage collection is unpredictable and any assumption on GC is misleading
Both answers are naive and are not guaranteed to work.
Garbage collection is unpredictable and you should not base your program logic around it. This should be used only for debugging, educational purposes or, if absolutely necessary, optimizations.
You can store your DisplayObjects in a WeakHashMap.
An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use.
The number of elements in the map will be the number of reachable objects or those which have not been garbage collected yet.
Add this in class:
public void finalize() {
super.finalize();
numOfObj-=1;
}
However, this method will be called only when system is collecting garbage. I mean, there can be a situation which the usage of the object is end, but system do not collect them so the method will not be called.
In a Java setter method that assigns a new Object to a field such as:
public class MyClass
{
private String s;
public void mySetter(String newS) {
s = newS;
}
}
Does the previous String s get garbage collected after mySetter is called or should I null out s before I assign it to the new value?
public class MyClass
{
private String s;
public void mySetter(String newS) {
s = null;
s = newS;
}
}
Does the previous String s get garbage collected after mySetter is called or should I null out s before I assign it to the new value?
If your previous String s is not referenced anywhere then it will be. But it won't happen immmedialtely after mySetter is called. No need to set it to null.
no need to null out, the garbage collector will find the string if no one else references it.
You don't have to do s = null; part. In Java a variable is in fact a reference to physical object in RAM memory. So when you do s = newS; you make a variable s point to a new object in RAM and the old object is no longer referenced by any of your variables and will be garbage collected.
Garbage collection will only happen when memory space is required by JVM
so in your case it will not be garbage collected as soon as your method gets called.
for more already an answer here
Also while assigning string to another value, you need not to set it to null first, as when you assign a new value to string means that now your reference variable is not pointing to previous value of the String object but to the new one and Java provides you the flexibility of not worrying about GC like other programming language. So don't try doing GC, Java can take care of it for you
After reading the books, surfing the nets regarding the type of references in Java, I still have some doubts (or I may have interpreted the concept wrong).
It would be a great help for me if anyone clear my doubts.
Let me take an example of a class containing class variables, instance variables and local variables.
public class Test {
public static ArrayList<String> listCommon = new ArrayList<String>();
private HashMap<String, String> mapInstance;
public Test() {
mapInstance = new HashMap<String, String>();
}
public void doSomething(String key) {
ArrayList<String> local = new ArrayList<String>();
if(key != null){
local.add(mapInstance.get(key));
}
System.out.println("Value is added in instance Map: ", mapInstance.get(key));
}
}
My Question are;
1. are listCommon (static variable) and mapInstance (instance variable) Strong reference towards Garbage Collector?
2. Is variable local (defined and used in method) a Weak reference?
3. How the Phantom reference and Soft reference came in picture?
4. OR above 3 concepts are invalid; means that Java defines the references only if you explicitly used the type defined in java.lang.ref package?
Any help would be great for me.
are listCommon (static variable) and mapInstance (instance variable) Strong reference towards Garbage Collector?
They are strong references, yes.
Is variable local (defined and used in method) a Weak reference?
No, it is a local variable, so it is a variable, so it is still a strong reference.
How the Phantom reference and Soft reference came in picture?
If you use them. If you don't use them you don't need to worry about them. They are for writing various kinds of caches really.
OR above 3 concepts are invalid; means that Java defines the references only if you explicitly used the type defined in
java.lang.ref package?
Reference variables are always strong. The other kinds only arise when you use them explicitly.
Answer to questions:
Yes, they are strong reference. Weak Reference are defined using Weak reference Object.
No, reason as 1).
Phantom Reference doesn't apply in your example. By default, all instances are strong reference.
Yes, you specify weak/phantom reference using the java.lang.ref package. By default, strong reference is used.
Note: A wikipedia explaination of Weak Reference might be useful.
Read this blog post about variable references.
** Update **
An atomic reference is an object referenced in such a way that it is accessed atomically; meaning that there are no race condition accessing it. For example:
class RaceTest {
static private int count = 0;
static public void main(String...args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i=0; i<1000000; i++) {
count++;
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
for (int i=0; i<1000000; i++) {
count--;
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count (should be 0) = " + count);
}
}
Will spawn two threads that 1) will increment count and 2) will decrement it. Now, both threads will run in parallel and the program will wait until both terminate (at the join point). A common idea would be that since both threads have the same loop (will loop the same amount of time), each will "cancel" each other's operation and thus count should be 0, but this is not the case. Why? Because while, for example, t1 may want to increase the variable, such operation is not atomic, but is more in the order of : get, inc, set. So there may be cases that, even before the second operation inc is made, t2 would have accessed the variable and dec the variable, thus t1 would have had actually +2 the variable. And vice versa in an indefinite manner. (Each run of the code would produce a different value.)
Now, replacing int by AtomicInteger and using incrementAndGet() or decrementAndGet() will solve the issue by rendering the get, inc, set into a single operation, and eliminating the race condition in the code.