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
Related
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.
Let's say we got an object and a static variable that counts the generated objects
variable = new Foo();
Foo.getObjCounter(); // -> 1
Is there a way in java to put this code:
variable = null;
Foo.decreaseFooCounter();
Into one method such as:
variable.delete();
Foo.getFooCounter(); // -> 0
or
Foo.delete(variable);
Foo.getFooCounter(); // -> 0
You can achieve such behaviour by using WeakReferences or more specific a Set backed by a WeakHashMap. See the following example:
class Foo {
private static final Set<Foo> references = Collections.newSetFromMap(new WeakHashMap<>());
public Foo() {
references.add(this); // register ourselves
}
public static int getFooCounter() {
return references.size();
}
// rest of the methods
}
Though the reference to the created Foo will only be removed if they have been free'd up by the garbage collector. To quote the doc:
[...] Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object [...]
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.
Is it possible to set to null an instance of a class within the class. For example, could I do something like this
int main{
//Create a new test object
Test test = new Test();
//Delete that object. This method should set the object "test" to null,
//thus allowing it to be called by the garbage collector.
test.delete();
}
public class Test{
public delete(){
this = null;
}
}
I have tried this and it does not work. Using "this = null" I get the error that the left hand side needs to be a variable. Is there a way to achieve something similar?
An instance of an object doesn't know which references might be referring to it, so there's no way that code within the object can null those references. What you're asking for isn't possible(*).
* at least not without adding a pile of scaffolding to keep track of all the references, and somehow inform their owners that they should be nulled - in no way would it be "Just for convenience".
You can do something like this
public class WrappedTest {
private Test test;
public Test getTest() { return test; }
public void setTest(Test test) { this.test = test; }
public void delete() { test = null; }
}
"this" is a final variable. you can not assign any values to it.
If you want to set the reference null you can do this
test = null;
this is a reference to the instance of your class. When you modify a reference variable, it only modifies that reference and nothing else. For example:
Integer a = new Integer(1);
Integer b = a;
a = new Integer(2); //does NOT modify variable b
System.out.println(b); //prints 1
Is it possible to set to null an instance of a class within the class?.
You cannot do this from the member methods of the same instance. So, this=null or that sort of thing will not work.
How come one set an instance to an null?
That question itself is wrong, we set references to null but not instances. Unused objects automatically garbage collected in java.
If you set test=null it will eventually gets garbage collected.
int main{
//Create a new test object
Test test = new Test();
// use the object through test
test=null;
}
I have a class that looks like:
public class BadCodeStyle {
private static String theAnswer = null;
public static void setAnswer(String whatsNew) {
theAnswer = whatsNew;
}
public static String getAnswer() {
return (theAnswer == null) ? "I don't know" : theAnswer;
}
}
Of course that's a simplification of the actual class. What really happens is that the static method retrieves a framework object if the variable is null. Setting the variable just serves to insert a mock value for test runs where I want to isolate the code from the framework (retrofitting code for testability is fun - like poking your own eye type of fun).
When I do BadCodeStyle.setAnswer("42") the static method behaves like a Singleton (?). I did read the classloader explanation and conclude: the variable will stay as long as the class is loaded and that would be as long as the JVM runs? Is that correct?
Static class variables live as long as the class definition is loaded. This is usually until the VM exits. However, there are other ways a class can be unloaded. See, for example, this thread and this one.
Static variables are common to all objects (shared) more precisely. it doesn't belong to any instance of class (objects). so its obvious that it cannot be garbage collected with objects.
class X
{
static string str;
}
X obj1 = new X();
X obj2 = new X();
when you define X.str compiler 'll say replace with Class reference.
But it belongs to Class object. we refer to it as Class variable too. (classloader loads the class)
so its single variable (singleton 's actually a pattern that uses single object [use private constructors and using a method to return that single object] )
As you read the memory is reclaimed only when the program is done. it doesn't get (reclaimed) garbage collected in between [Non used objects 'll be garbage collected normally] .
so its lifetime exists as long as the process exists [program is running].
checkout lifetime of variables: www.cs.berkeley.edu/~jrs/4/lec/08