Nulling an object

F

Frank Cisco

If you null and object ie. obj = null, when is it cleared from memory?
Immediately or at the next garbage collection?
 
A

Arne Vajhøj

Frank said:
If you null and object ie. obj = null, when is it cleared from memory?
Immediately or at the next garbage collection?

You null a ref to an object. The object that the ref previously
pointed to will be GC'ed after that assuming that there are no other
refs to it.

Note that there is very rarely any use for explicit nulling
in Java. Having the ref not being ref'ed any more is sufficient.

Arne
 
K

Knute Johnson

Frank said:
If you null and object ie. obj = null, when is it cleared from memory?
Immediately or at the next garbage collection?

When the garbage collector decides to collect it. It really doesn't
matter to you and setting it to null isn't really necessary and may not
do anything for you anyway.
 
L

Lew

You null a ref to an object. The object that the ref previously
pointed to will be GC'ed after that assuming that there are no other
refs to it.

To amplify on what Arne said, you don't "null an object". That doesn't exist.

After all references ("refs") to an object disappear, the object might be
reclaimed by garbage collection (GC). Or it might not. Ever.
Note that there is very rarely any use for explicit nulling
in Java. Having the ref not being ref'ed any more is sufficient.

There are occasional exceptions, as explained by Josh Bloch in /Effective
Java/, Item 6 - essentially when you have logic that manages memory in a way
additional to mere allocation, you have to dereference such extra management.
Put more clearly, when you have hidden references to an object, such as in a
collection like a Stack, those references keep an object alive even after the
program is through with it. That's called "unintentional object retention",
or "packratting". You might have to null out those hidden references, but
other than in that specific situation you don't have to and shouldn't.
 
T

Tom Anderson

You null a ref to an object. The object that the ref previously
pointed to will be GC'ed after that assuming that there are no other
refs to it.

Note that there is very rarely any use for explicit nulling in Java.
Having the ref not being ref'ed any more is sufficient.

The only time it's important is where you have a reference from a
long-lived structure to a large structure that you no longer need. The
long-lived structure can be an object or a stack frame. If you're writing
a class where the lifetime is unknown (a library class, say), and the size
of the referent is large or unknown, i think it's prudent to null out the
variable when you can. ArrayList nulls out slots in its array when
elements are removed, for example; ISTR that an early version didn't, and
that this led to hard-to-debug memory leaks.

An example of the stack frame case was a program i worked on a little
while ago which looked like:

public void main(String[] args) {
BigXMLDocument conf = loadConfigFile();
Problem prob = initialiseProblem(conf);
prob.solve();
printResult(prob);
}

The XML tree for the config file wasn't needed after the creation of the
problem object, but because the reference to it was still live, it
couldn't be collected, and so sat around wasting memory while the
long-running solve method ran. Explicitly setting the variable to null
before going into solve would have avoided this.

However, what we actually did was to simply do an extract method
refactoring on the first two lines. That pushed the reference down into a
stack frame which died before solve was called, and shaved tens of
megabytes (woo!) off the heap usage. Where you can do this, it's more
elegant than explicit nulling - putting short-lived things on the stack is
generally a good idea.

tom
 
L

Lew

Tom said:
You null a ref to an object. The object that the ref previously
pointed to will be GC'ed after that assuming that there are no other
refs to it.

Note that there is very rarely any use for explicit nulling in Java.
Having the ref not being ref'ed any more is sufficient.

The only time it's important is where you have a reference from a
long-lived structure to a large structure that you no longer need. The
long-lived structure can be an object or a stack frame. If you're
writing a class where the lifetime is unknown (a library class, say),
and the size of the referent is large or unknown, i think it's prudent
to null out the variable when you can. ArrayList nulls out slots in its
array when elements are removed, for example; ISTR that an early version
didn't, and that this led to hard-to-debug memory leaks.

An example of the stack frame case was a program i worked on a little
while ago which looked like:

public void main(String[] args) {
BigXMLDocument conf = loadConfigFile();
Problem prob = initialiseProblem(conf);
prob.solve();
printResult(prob);
}

The XML tree for the config file wasn't needed after the creation of the
problem object, but because the reference to it was still live, it
couldn't be collected, and so sat around wasting memory while the
long-running solve method ran. Explicitly setting the variable to null
before going into solve would have avoided this.

So would have
Problem prob = initialiseProblem( loadConfigFile() );

Uglier, but also effective:

Problem prob;
{
BigXMLDocument conf = loadConfigFile();
prob = initialiseProblem(conf);
}
prob.solve();

etc.
However, what we actually did was to simply do an extract method
refactoring on the first two lines. That pushed the reference down into
a stack frame which died before solve was called, and shaved tens of
megabytes (woo!) off the heap usage. Where you can do this, it's more
elegant than explicit nulling - putting short-lived things on the stack
is generally a good idea.

This is much better than explicit nulling.
 
M

Mike Schilling

Lew said:
This is much better than explicit nulling.

Why? I'd think

document = null; // Allow the document to be collected

makes the intent clearer than

doInit();

giving the reader no clue why that part of the initialization logic
was put into a seperate method.
 
L

Lew

Tom said:
However, what we actually did was to simply do an extract method
refactoring on the first two lines. That pushed the reference down
into a stack frame which died before solve was called, and shaved
tens of megabytes (woo!) off the heap usage. Where you can do this,
it's more elegant than explicit nulling - putting short-lived
things

Mike said:
Why? I'd think

document = null; // Allow the document to be collected

makes the intent clearer than

doInit();

giving the reader no clue why that part of the initialization logic
was put into a seperate method.

What intent? To uselessly help the GC?

The closing brace gives ample clarity to the intent that a variable go out of
scope.

Explicit nulling implies that such a thing is necessary to the logic of the
program, a false implication in most cases. Putting almost any explicit logic
in to "help" GC is a red herring, not germane to the business logic of the
code. Ergo, documenting such non-germane code is only compounding the error.

Authors like Brian Goetz refer to explicit nulling as a mistake:
Sun warned of this risk [reference retention] and explained how explicit
nulling was needed in cases like the pop() example above. Unfortunately,
programmers often take this advice too far, using explicit nulling in the
hope of helping the garbage collector. But in most cases, it doesn't help
the garbage collector at all, and in some cases, it can actually hurt your
program's performance. ....
Explicit nulling should be saved for cases where your program is subverting
normal scoping rules for performance reasons, such as the stack example in
Listing 3
 
L

Lew

Peter said:
In fact, even the example Lew gives of a Stack is in reality unlikely to
require specific handling. In particular, if you're actually _done_

Joshua Bloch and Brian Goetz and Sun generally disagree with you. If the
Stack lives a long time, items being popped from it might need to have the
popped element in the Stack nulled out, or else the stack itself keeps the
object reachable, depending on the implementation.
<http://www.ibm.com/developerworks/library/j-jtp01274.html>,
which references
<http://java.sun.com/developer/TechTips/1997/tt0903.html#tip2>
Item 6 of /Effective Java/ makes substantially the same point, with a more
thorough explanation.
with the Stack, simply getting rid of the reference to the Stack itself
is sufficient for releasing all the objects that the Stack itself
references. Once the Stack becomes unreachable, so too do all the
objects the Stack references (assuming they aren't referenced elsewhere,
of course). It's only if you intend to retain the Stack, but no longer
want the objects to which it refers do you need to do any clearing of
references (and of course, the most direct way to do that is simply to
call the clear() method).

(Of course, in the real world a Stack is usually not discarded until
empty, at which point it doesn't have references to other objects
anyway, but that's not really germane to the point here :) ).

It is germane in the reverse, wherein the Stack is not yet discarded but you
wish references above the current top of stack to be.

The key is that constructs like Stack and Map take over part of the memory
management burden and hold on to references in ways that the programmer might
forget. This "packratting", long-lived structures holding on to
now-irrelevant references, is the source of so-called "memory leaks" in Java.

Goetz, in the above-referenced DeveloperWorks article, cautions against taking
this principle too far.

Another solution to packratting involves WeakReferences.
 
M

Mike Schilling

Lew said:
Tom said:
However, what we actually did was to simply do an extract method
refactoring on the first two lines. That pushed the reference
down
into a stack frame which died before solve was called, and shaved
tens of megabytes (woo!) off the heap usage. Where you can do
this,
it's more elegant than explicit nulling - putting short-lived
things




What intent? To uselessly help the GC?


The closing brace gives ample clarity to the intent that a variable
go out of scope.

We were specifically discussing the case where it is necessary,
because the variable won't go out of scope anytime soon. This can
also occur with nested scopes within a method, since variables within
them don't go "out of scope" for GC purposes until the method returns.

Explicit nulling implies that such a thing is necessary to the logic
of the program, a false implication in most cases. Putting almost
any explicit logic in to "help" GC is a red herring, not germane to
the business logic of the code. Ergo, documenting such non-germane
code is only compounding the error.

The most important code to comment is that put in for an important but
non-obvious reason .
 
M

Mike Schilling

Peter said:
In fact, even the example Lew gives of a Stack is in reality
unlikely
to require specific handling. In particular, if you're actually
_done_ with the Stack, simply getting rid of the reference to the
Stack itself is sufficient for releasing all the objects that the
Stack itself references.

The issue witrh stacks (and ArrayLists) is that a naive implementation
retains unnecessary references to objects. Assume something like:
(not tested or compiled, so please ignore any typos, as well as the
fact that neither overflow nor underflow is handled.)

public class SimpleStack
{
private Object stack[] = new Object[MAX_SIZE];
int size = 0;

public void push(Object o)
{
stack[++size] = o;
}

public Object pop()
{
return stack[--size];
}
}

If you push three objects and then pop two of them, the stack still
references all three, and will continue to do so for an indefinite
period of time. The solution is to replace pop() with

public Object pop()
{
Object o = stack[--size];
stack[size] = null; // remove reference to o.
return o;
}

Having popped an object, the stack should forget about it completely.
 
L

Lew

Mike said:
We were specifically discussing the case where it is necessary,
because the variable won't go out of scope anytime soon. This can

That sounds like it would be better fixed by properly scoping the variable
than by a null-assignment hack. In the specific discussion to which you
refer, that was the answer in fact; Tom Anderson discussed how his project
solved it by a far better means than the null-assignment hack.
also occur with nested scopes within a method, since variables within
them don't go "out of scope" for GC purposes until the method returns.

In all JVM implementations? In the presence of Hotspot? Forever more?

Normally the source should not make assumptions specific to a particular
version of the JVM. In the case of a putative optimization, there should be
measurement and evidence first, re-evaluation of the algorithm second, and
micro-optimization third. Tom Anderson's anecdote was a good example; it
showed how changing the algorithm solved the measured performance problem
without resorting to implementation-specific hacks.

In light of the experts' advice that indiscriminate use of null assignment is
superfluous and occasionally harmful, I'd look for a very strong reason to do
otherwise.
 
L

Lew

Peter said:
Whether those you named disagree with me depends on what they consider a
bug-free implementation of a stack.

They consider a bug-free implementation to be that which follows their advice.
It is the implementation that requires "specific handling", as I've been
saying right along.
I would say that a stack implementation that retains a reference to an
object popped or otherwise cleared from the stack is not bug-free.

But then we agree here. I am discussing the implementation of the stack, not
its use. That was clear from the examples I linked, which discuss stack
implementation, not use.
But yes, if you're dealing with a buggy stack implementation, you might
have to go to extra work to ensure your popped object really is no

I refer to the work done by the stack implementation itself, not by the
clients of the stack, as do the examples that I cited.
longer referenced by the stack. What that "extra work" might be would
depend on the implementation, but in the most obvious case would involve
pushing and then immediately popping a null reference.

No, that is from the perspective of the stack client. The stack
implementation has to null the outdated reference as part of the 'pop()'
implementation. See the examples that I cited.
My comments are all intended to be in the context of assuming a bug-free
implementation. YMMV.

And my comments are all intended to be in the context of one writing that
implementation to ensure that clients may safely make that assumption.
 
M

Mike Schilling

Lew said:
That sounds like it would be better fixed by properly scoping the
variable than by a null-assignment hack. In the specific discussion
to which you refer, that was the answer in fact; Tom Anderson
discussed how his project solved it by a far better means than the
null-assignment hack.

In all JVM implementations? In the presence of Hotspot? Forever
more?

That's how it's been documented.
Normally the source should not make assumptions specific to a
particular version of the JVM.

Though it's only sensible to put in workarounds for issues with JVMs
that the code is going to be run on, provided that they're
well-documented. Code runs on real JVMs, not hypotherical perfect
ones.
In the case of a putative
optimization, there should be measurement and evidence first,
re-evaluation of the algorithm second, and micro-optimization third.
Tom Anderson's anecdote was a good example; it showed how changing
the algorithm solved the measured performance problem without
resorting to implementation-specific hacks.

Not at all. It was an example of another way to solve the problem
that Tom felt was more "elegant". I disagree, and don't see why my
criteria of making the problem and its solution clear in the code are
of less value than Tom's (and apparently your) esthetic feelings.
 
T

Tom Anderson

Why? I'd think

document = null; // Allow the document to be collected

makes the intent clearer than

doInit();

giving the reader no clue why that part of the initialization logic
was put into a seperate method.

The initialisation code that was pulled out was all the stuff to do with
parsing XML. That seems like a pretty natural unit of separation to me,
and not something needing comment - the reduced memory footprint was a
nice side-effect of cleaner organisation, even if the motivations weren't
that way round. If the stuff pulled out was less of a natural unit,
perhaps you'd be right.

tom
 
L

Lew

Peter said:
[...]
My comments are all intended to be in the context of assuming a
bug-free implementation. YMMV.

And my comments are all intended to be in the context of one writing
that implementation to ensure that clients may safely make that
assumption.

You should have made that clear from the outset then. Your statement
was: "when you have hidden references to an object, such as in a
collection like a Stack, those references keep an object alive even
after the program is through with it".

You wrote "a collection like a Stack", not "an implementation of a
stack". The built-in Stack class surely does not have that particular bug.

Christ, Peter, I said *in* the collection and *like* a Stack, and I pointed to
two examples that discussed the implementation, not the use. Sheesh.

I was making it clear.
 
F

Frank Cisco

Frank Cisco said:
If you null and object ie. obj = null, when is it cleared from memory?
Immediately or at the next garbage collection?

Cheers for the responses. I guess the only way to say whether this is an
effective practice is to see how the GC does it's work - maybe helping the
GC out isn't such a bad idea. I've noticed a lot of null setting in the core
java APIs - so it can't be that harmful. Anyone from Sun Microsystems about?
 
L

Lew

Peter said:
And frankly, I could have tolerated the comments, except that
you insisted on making it about how what I had written was _wrong_,

That's not what I made it about, and certainly nothing I was insisting on. It
just seemed that way because we were in utterly different contexts. It was
about whether structures like Stack were unlikely to require special handling
- it was an attempt to get at the truth. To that end I cited experts, indeed
the very ones who wrote relevant parts of the Java API that dealt with this
issue, who spoke of when one needs to null out references and when one doesn't.

I've reviewed my posts in this thread, and they make no special effort to
claim that what you wrote was wrong. They just continually cited examples of
how to implement stacks and such without packratting. When I found that I was
not making my context clear, I clarified it and pointed out that we agree.
How would I be making what you wrote wrong and also claiming to agree with it?
when in fact nothing I wrote was wrong.

What you wrote about nulling out references was not wrong.
 
V

Volker Borchert

Peter said:
The reason that one does not normally need to be concerned is that what's
important is whether the object is reachable, not whether references to it
exist. You can have a very complicated data structure, but which is
referenced at the root by a single object reference. Once you're done
with that data structure, there's no need to traverse it, nulling out
references. As long as the root reference is discarded (which may in fact
involve nulling out a single reference), the rest of the data structure is
no longer reachable, and thus is automatically eligible for garbage
collection with no special effort from the program.

In fact, traversal to null out may have the following drawbacks:
0. It is unnecessary work for the CPU, and causes unnecessary
cache and/or memory writes.
1. It may reference memory pages that have been flushed out of the
cache or even swapped out to disk, causing expensive refresh or
swap operations.
2. It may actually interfere with some types of garbage collectors
that keep track which memory areas have been recently updated
or traversed into.
 
K

Karl Uppiano

Frank Cisco said:
If you null and object ie. obj = null, when is it cleared from memory?
Immediately or at the next garbage collection?

I have been programming in Java since ca. 1995, and I have never once
bothered myself with "helping" GC. It is my considered opinion that GC is
supposed to be automatic. If I wanted to worry about memory management, I
would program in C++. Actually, I sometimes do, but I digress.

In 15 years, I have had two sources of "memory leaks" in Java, both due to
programmer error: Threads not actually terminating, and thus keeping
references to all sorts of resources attached to them, and collections that
still contained items that should have been removed. I've never encountered
a need to explicitly null out any references. I suppose there are certain
corner cases that would require it:

- The stack example (although failure of a stack to truly unreference a
popped element would be unexpected and, I hope, clearly documented)
- Objects created near the head of the call stack (say, main) that remain in
scope for a very long time, even though they are no longer needed. I suspect
that there are ways of organizing the code so as to eliminate that behavior,
but perhaps just setting the reference to null when finished with it is the
simplest thing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top