final and memory leak - java

As far as I know final tells the CPU that it can caches the variable/object (It anyway differs from CPU to CPU. I think x86 CPU-s are really doing a core cache L1)
My question is:
In the following example I have an object myObjectFinal set as final so the CPU can cache it and then it changes a value inside. Does this mean that myObject is not guaranteed to be also changed?
Does the reference gets broken if I set final and the CPU decide to cache it?
What if I change myObject, is the cached final guaranteed to get also changed?
// thread 1
volatile MyObject myObject = new MyObject();
// thread 2
final MyObject myObjectFinal = myObject;
myObjectFinal.setData(1);
// thread 1
myObject.setData(2);
Maybe the code does not tell exactly what I mean. So, the main question is: Does making a mutable object final or volatile have any repercussions to how the object is cached by the CPU. If it does then when I should use final or volatile on mutable objects?
Does the CPU ever caches a mutable object or final/volatile have absolutely no effect on them and are used only for coding consistency?

final means, that the value cannot be changed after initialization.
Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.
https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4
so unless you reassign myObjectFinal, nothing bad will happen,
However if you change the same object from multiple threads, you will need synchronization. (don't use volatile)
First of all, get rid of the object-orientation. An objects is a virtual construct. we are talking about low-level stuff like registers and caches - there are only primitives (every class can be reduced to a set of primitives)
The reason, why we need caches is simple.
The memory is just horrible slow. So the idea is to reduce the number of memory-accesses to a minimum.
consider the following code:
1. x=0;
2. if (x == 1)
3. x++
inside of your normal computer now happens something like this (without register-optimization)
1. write 0 into a register
write the register into the memory
2. read x from the memory into a CPU-register
compare it with 1 and go to 3 or 4
3. read x from the memory into a CPU-register
increment register
write the register into the memory
a lot of redundant memory operations ... but you can eliminate them
1. write 0 into a register
write the register into the memory
2. compare the register with 1 and go to 3 or 4
3. increment register
write the register into the memory
we keep the value of x in the register. So why not keep all variables in registers? first of all there arent that many registers available, so you cannot store everything there. Its more a temporary thing to hold a variable in a register. (inside a scope for example)
The other problem is, that no other core and/or device can read from the registers. then you need to reload/write-back the variable.
if you declare a variable as final, it will never be changed. So the variable could be stored in a register without having a problem with inconsistency. However this does not mean, that other threads cannot access the variable, since its also stored inside of the memory. Its guaranteed that the value in the memory is always valid. But all variables regardless of being final or not, can and will be stored for a short time in registers. thats why we need to use a synchronization-tool, which forces the write-back from the registers to the memory, if you want to guarantee the consistency on multiple threads/cores.
however the real CPU-cache, is a complete different topic. its a complete transparent system (executes on hardware-side!), which is only affected by the memory-access-pattern (unless you really do some crazy low-low level-stuff in assembly). To make it short here: The CPU-cache basically caches every byte, unless you explicit force it to not do it.

Related

volatile vs final fields performance

What is preferable for performance? Assume no to little contention
mutable class with volatile fields and updating them one by one
immutable class with final fields, an update cycle avoids the
multi-field update and instead re-creates the class once
Volatiles require memory barriers on every write, I suppose the same is true for final fields? Meaning a single memory barrier upon object construction?
Update for clarification:
I feel the question is valuable on its own and answerable generically, taking into account the java memory model and current gen hardware. If you must assume specifics:
the object is of course accessed from multiple threads, otherwise this exercise would be pointless
a single object is long-lived, as in multiple hours
there are hundreds to thousands of those objects, with hundreds to thousands of update events per second
final is a hint to the compiler that the field value cannot change. Any write attempts are caught at compile time. Reading a final value does not use a memory barrier. You cannot write to a final variable, so a memory barrier is meaningless.
Using the hint, the compiler (or the JIT) may replace a memory reference to a final value with a constant. So in terms of performance, final does not introduce any additional overhead.
If the garbage-collector flushes every thread's cache between the last time an old object is accessed and the space being made available for a new object, and if no cache line contains data from multiple objects, then it would on most platforms be naturally impossible for a newly-constructed object to get loaded into any thread's cache before a reference to that object is stored in a location which is accessible to that thread, even in the absence of any read barriers (beyond the aforementioned once-per-GC-cycle system-wide barrier). Further, if a compiler can tell that writes occur to multiple fields of an object will occur without any intervening writes to any other object whose reference may have been exposed, it could omit write barriers for all but the last.
The only time using final fields would be more expensive than volatile would be if it necessitated the creation of more objects to handle changes which could have been done "in place" with volatile fields. Since many factors can affect object-creation cost, the only reliable way to judge which approach is more efficient under a particular set of circumstances on a particular system would often benchmark both.

Do uninitialized primitive instance variables use memory?

In Java, does it cost memory to declare a class level instance variable without initializing it?
For example: Does int i; use any memory if I don't initialize it with i = 5;?
Details:
I have a huge super-class that many different (not different enough to have their own super classes) sub-classes extend. Some sub-classes don't use every single primitive declared by the super-class. Can I simply keep such primitives as uninitialized and only initialize them in necessary sub-classes to save memory?
All members defined in your classes have default values, even if you don't initialize them explicitly, so they do use memory.
For example, every int will be initialized by default to 0, and will occupy 4 bytes.
For class members :
int i;
is the same as :
int i = 0;
Here's what the JLS says about instance variables :
If a class T has a field a that is an instance variable, then a new instance variable a is created and initialized to a default value (§4.12.5) as part of each newly created object of class T or of any class that is a subclass of T (§8.1.4). The instance variable effectively ceases to exist when the object of which it is a field is no longer referenced, after any necessary finalization of the object (§12.6) has been completed.
Yes, memory allocates though you are not assigning any value to it.
int i;
That takes 32 bit memory (allocation). No matter you are using it or not.
Some sub-classes don't use every single primitive declared by the super-Class. Can I simply keep such primitives as uninitialized and only initialize them in necessary sub-classes to save memory?
Again, no matter where you initialized, the memory allocates.
Only thing you need to take care is, just find the unused primitives and remove them.
Edit:
Adding one more point that unlike primitive's references by default value is null, which carries a a memory of
4 bytes(32-bit)
8 bytes on (64-bit)
The original question talks about class level variables and the answer is that they do use space, but it's interesting to look at method scoped ones too.
Let's take a small example:
public class MemTest {
public void doSomething() {
long i = 0; // Line 3
if(System.currentTimeMillis() > 0) {
i = System.currentTimeMillis();
System.out.println(i);
}
System.out.println(i);
}
}
If we look at the bytecode generated:
L0
LINENUMBER 3 L0
LCONST_0
LSTORE 1
Ok, as expected we assign a value at line 3 in the code, now if we change line 3 to (and remove the second println due to a compiler error):
long i; // Line 3
... and check the bytecode then nothing is generated for line 3. So, the answer is that no memory is used at this point. In fact, the LSTORE occurs only on line 5 when we assign to the variable. So, declaring an unassigned method variable does not use any memory and, in fact, doesn't generate any bytecode. It's equivalent to making the declaration where you first assign to it.
Yes. In your class level variables will assign to its default value even if you don't initialize them.
In this case you int variables will assign to 0 and will occupied 4 bytes per each.
Neither the Java Language Specification nor the Java Virtual Machine Specification specifies the answer to this because it's an implementation detail. In fact, JVMS §2.7 specifically says:
Representation of Objects
The Java Virtual Machine does not mandate any particular internal structure for objects.
In theory, a conformant virtual machine could implement objects which have a lot of fields using set of bit flags to mark which fields have been set to non-default values. Initially no fields would be allocated, the flag bits would be all 0, and the object would be small. When a field is first set, the corresponding flag bit would be set to 1 and the object would be resized to make space for it. [The garbage collector already provides the necessary machinery for momentarily pausing running code in order to relocate live objects around the heap, which would be necessary for resizing them.]
In practice, this is not a good idea because even if it saves memory it is complicated and slow. Access to fields would require temporarily locking the object to prevent corruption due to multithreading; then reading the current flag bits; and if the field exists then counting the set bits to calculate the current offset of the wanted field relative to the base of the object; then reading the field; and finally unlocking the object.
So, no general-purpose Java virtual machine does anything like this. Some objects with an exorbitant number of fields might benefit from it, but even they couldn't rely on it, because they might need to run on the common virtual machines which don't do that.
A flat layout which allocates space for all fields when an object is first instantiated is simple and fast, so that is the standard. Programmers assume that objects are allocated that way and thus design their programs accordingly to best take advantage of it. Likewise, virtual machine designers optimize to make that usage fast.
Ultimately the flat layout of fields is a convention, not a rule, although you can rely on it anyway.
In Java, when you declare a class attribute such as String str;, you are declaring a reference to an object, but it is not pointing yet to any object unless you affect a value to it str=value;. But as you may guess, the reference, even without pointing to a memory place, consumes itself some memory.

Are final fields really useful regarding thread-safety?

I have been working on a daily basis with the Java Memory Model for some years now. I think I have a good understanding about the concept of data races and the different ways to avoid them (e.g, synchronized blocks, volatile variables, etc). However, there's still something that I don't think I fully understand about the memory model, which is the way that final fields of classes are supposed to be thread safe without any further synchronization.
So according to the specification, if an object is properly initialized (that is, no reference to the object escapes in its constructor in such a way that the reference can be seen by another thread), then, after construction, any thread that sees the object will be guaranteed to see the references to all the final fields of the object (in the state they were when constructed), without any further synchronization.
In particular, the standard (http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4) says:
The usage model for final fields is a simple one: Set the final fields
for an object in that object's constructor; and do not write a
reference to the object being constructed in a place where another
thread can see it before the object's constructor is finished. If this
is followed, then when the object is seen by another thread, that
thread will always see the correctly constructed version of that
object's final fields. It will also see versions of any object or
array referenced by those final fields that are at least as up-to-date
as the final fields are.
They even give the following example:
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
In which a thread A is supposed to run "reader()", and a thread B is supposed to run "writer()".
So far, so good, apparently.
My main concern has to do with... is this really useful in practice? As far as I know, in order to make thread A (which is running "reader()") see the reference to "f", we must use some synchronization mechanism, such as making f volatile, or using locks to synchronize access to f. If we don't do so, we are not even guaranteed that "reader()" will be able to see an initialized "f", that is, since we have not synchronized access to "f", the reader will potentially see "null" instead of the object that was constructed by the writer thread. This issue is stated in http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalWrong , which is one of the main references for the Java Memory Model [bold emphasis mine]:
Now, having said all of this, if, after a thread constructs an
immutable object (that is, an object that only contains final fields),
you want to ensure that it is seen correctly by all of the other
thread, you still typically need to use synchronization. There is no
other way to ensure, for example, that the reference to the immutable
object will be seen by the second thread. The guarantees the program
gets from final fields should be carefully tempered with a deep and
careful understanding of how concurrency is managed in your code.
So if we are not even guaranteed to see the reference to "f", and we must therefore use typical synchronization mechanisms (volatile, locks, etc.), and these mechanisms do already cause data races to go away, the need for final is something I would not even consider. I mean, if in order to make "f" visible to other threads we still need to use volatile or synchronized blocks, and they already make internal fields be visible to the other threads... what's the point (in thread safety terms) in making a field final in the first place?
I think that you are misunderstanding what the JLS example is intended to show:
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could see 0
}
}
This code does not guarantee that the latest value of f will be seen by the thread that calls reader(). But what it is saying is that if you do see f as non-null, then f.x is guaranteed to be 3 ... despite the fact that we didn't actually do any explicit synchronizing.
Well is this implicit synchronization for finals in constructors useful? Certainly it is ... IMO. It means that we don't need to do any extra synchronization each time we accessed an immutable object's state. That is a good thing, because synchronization typically entails cache read-through or write-through, and that slows your program down.
But what Pugh is saying is that you will typically need to synchronize to get hold of the reference to the immutable object in the first place. He is making the point that using immutable objects (implemented using final) does not excuse you from the need to synchronize ... or from the need to understand the concurrency / synchronization implementation of your application.
The problem is that we still need to be sure that reader will se a non-null "f", and that's only possible if we use other synchronization mechanism that will already provide the semantics of allowing us to see 3 for f.x. And if that's the case, why bother using final for thread safety stuff?
There is a difference between synchronizing to get the reference and synchronizing to use the reference. The first one I may need to do only once. The second one I may need to do lots of times ... with the same reference. And even if it is one-to-one, I have still halved the number of synchronizing operations ... if I (hypothetically) implement the immutable object as thread-safe.
TL;DR: Most software developers should ignore the special rules regarding final variables in the Java Memory Model. They should adhere to the general rule: If a program is free of data races, all executions will appear to be sequentially consistent. In most cases, final variables can not be used to improve the performance of concurrent code, because the special rule in the Java Memory Model creates some additional costs for final variables, what makes volatile superior to final variables for almost all use cases.
The special rule about final variables prevents in some cases, that a final variable can show different values. However, performance-wise the rule is irrelevant.
Having said that, here is a more detailed answer. But I have to warn you. The following description might contain some precarious information, that most software developers should never care about, and it's better if they don't know about it.
The special rule about final variables in the Java Memory Model somehow implies, that it makes a difference for the Java VM and Java JIT compiler, if a member variable is final or if it's not.
public class Int {
public /* final */ int value;
public Int(int value) {
this.value = value;
}
}
If you take a look at the Hotspot source code, you will see that the compiler checks if the constructor of a class writes at least one final variable. If it does so, the compiler will emit additional code for the constructor, more precisely a memory release barrier. You will also find the following comment in the source code:
This method (which must be a constructor by the rules of Java)
wrote a final. The effects of all initializations must be
committed to memory before any code after the constructor
publishes the reference to the newly constructor object.
Rather than wait for the publication, we simply block the
writes here. Rather than put a barrier on only those writes
which are required to complete, we force all writes to complete.
That means the initialization of a final variable is similar to a write of a volatile variable. It implies some kind of memory release barrier. However, as can be seen from the quoted comment, final variables might be even more expensive. And what's even worse, you have these additional costs for final variables regardless whether they are used in concurrent code or not.
That's awful, because we want software developers to use final variables in order to increase the readability and maintainability of source code. Unfortunately, using final variables can significantly impact the performance of a program.
The question remains: Are there any use cases where the special rule regarding final variables helps to improve the performance of concurrent code?
That's hard to tell, because it depends on the actual implementation of the Java VM and the memory architecture of the machine. I haven't seen any such use cases until now. A quick glance at the source code of the package java.util.concurrent has also revealed nothing.
The problem is: The initialization of a final variable is about as expensive as a write of a volatile or atomic variable. If you use a volatile variable for the reference of the newly created object, you get the same behaviour and costs with the exception, that the reference will also be published immediately. So, there is basically no benefit in using final variables for concurrent programming.
You are right, since locking makes stronger guarantees, the guarantee about availability of finals is not particularly useful in the presence of locking. However, locking is not always necessary to ensure reliable concurrent access.
As far as I know, in order to make thread A (which is running "reader()") see the reference to "f", we must use some synchronization mechanism, such as making f volatile, or using locks to synchronize access to f.
Making f volatile is not a synchronization mechanism; it forces threads to read the memory each time the variable is accessed, but it does not synchronize access to a memory location. Locking is a way to synchronize access, but it is not necessary in practice to guarantee that the two threads share data reliably. For example, you could use a ConcurrentLinkedQueue<E> class, which is a lock-free concurrent collection* , to pass data from a reader thread to a writer thread, and avoid synchronization. You could also use AtomicReference<T> to ensure reliable concurrent access to an object without locking.
It is when you use lock-free concurrency that the guarantee about the visibility of final fields come in handy. If you make a lock-free collection, and use it to store immutable objects, your threads would be able to access the content of the objects without additional locking.
* ConcurrentLinkedQueue<E> is not only lock-free, but also a wait-free collection (i.e. a lock-free collection with additional guarantees not relevant to this discussion).
Yes final final fields are useful in terms of thread-safety. It may not be useful in your example, however if you look at the old ConcurrentHashMap implementation the get method doesn't apply any locking while it search for the value, though there is a risk that while look up is happening the list might change (think of ConcurrentModificationException ). However CHM uses the list made of final filed for 'next' field guaranteeing the consistency of the list (the items in the front/yet-to see will not grow or shrink). So the advantage is thread-safety is established without synchronization.
From the article
Exploiting immutability
One significant source of inconsistency is avoided by making the Entry
elements nearly immutable -- all fields are final, except for the
value field, which is volatile. This means that elements cannot be
added to or removed from the middle or end of the hash chain --
elements can only be added at the beginning, and removal involves
cloning all or part of the chain and updating the list head pointer.
So once you have a reference into a hash chain, while you may not know
whether you have a reference to the head of the list, you do know that
the rest of the list will not change its structure. Also, since the
value field is volatile, you will be able to see updates to the value
field immediately, greatly simplifying the process of writing a Map
implementation that can deal with a potentially stale view of memory.
While the new JMM provides initialization safety for final variables,
the old JMM does not, which means that it is possible for another
thread to see the default value for a final field, rather than the
value placed there by the object's constructor. The implementation
must be prepared to detect this as well, which it does by ensuring
that the default value for each field of Entry is not a valid value.
The list is constructed such that if any of the Entry fields appear to
have their default value (zero or null), the search will fail,
prompting the get() implementation to synchronize and traverse the
chain again.
Article link: https://www.ibm.com/developerworks/library/j-jtp08223/

Java: Allocation of new objects and cache coherency

In Java, suppose you have two threads T1 and T2 running simultaneously on two different processors P1 and P2.
At first, thread T2 works with some object obj that is allocated at (say) starting memory location 0x1000. This causes P2 to internally cache the value at that memory location. T2 then nulls out the (only) reference to the object and it is garbage collected.
Thread T1 then does
Foo fooRef = new Foo();
fooRef.x = 10;
and it just happens that fooRef.x's location is also at 0x1000, because this instance of Foo was allocated re-using memory that was freed by T2 above.
T1 then passes the fooRef reference to thread T2 (via a queue, or some other shared memory mechanism).
Will T2 see the old stale cached value from before, or will it see the new value of 10?
Let's say there is no hardware cache coherency mechanism. Does Java itself ensure the clearing of every processors' cache when it deallocates or allocates memory for an object? (Even with a hardware cache coherency mechanism in place, the coherency propagation is not instantaneous, and T2 might still happen to read the stale value, if no other coherency measures by Java itself are taken).
If you don't properly synchronise, then T2 could in principle see one of three things (not necessarily with equal probability):
(a) an apparently correctly formed object, but containing incorrect data;
(b) an object that isn't properly formed in the first place (i.e. never mind your data, the actual housekeeping metadata belonging to the object is not properly visible, potentially causing "bad things to happen");
(c) accidentally, you "dodge the bullet" as it were and T2 sees the object as T1 left it.
If you properly synchronise (or put another way, properly publish the object) then T2 will see the object as T1 defined it. In this article on the final keyword and further articles linked to at the bottom, I discuss some of the issues and solutions. Some of this answers to this previous question on What is object publishing and why do we need it? may also help.
So, practically[*] all of the time, you need to properly synchronise. It is dangerous to try and guess which of the situations (a), (b) or (c) will occur if you don't properly synchronise.
[*] There are very occasional advanced techniques where synchronisation can be safely avoided if you can genuinely calculate all of the possible "paths" resulting from lack of synchronisation, such as a technique referred to as synchronisation piggybacking where you effectively know that synchronisation will be performed 'in time' somewhere else. I recommend you don't go down this route!
You will not see "junk" left over from the first object.
Each primitive in the object will contain either its initial value (0, false, etc) or some value that had been put there at some point -- though reordering may produce weird mixes of values. Additionally, if a primitive is a two-word value (long or double), you may see only one of those words updated: this could produce a value that no thread has ever put there, but it's consistent with the above in that you are seeing the effects of a write to this object -- you're just not seeing all of that write. But you're still not seeing the effects of a write on some totally other, random object.
For reference values, you'll either see the initial value (null) or a correct reference to a constructed object -- though that object's values are subject to the same vague rules as above (they can be either the initial value or any other value some other thread has put in, with reorderings etc allowed).
Now, I can't actually find the exact place in the JLS where this is written. But there are several parts that strongly imply it. For instance, JLS 17.4.5 states in an example:
Since there is no synchronization, each read can see either the write of the initial value or the write by the other thread.
Emphasis mine, but note that it lists the values that the read can see; it doesn't say "each read can see anything, including junk bytes left over from previous objects."
Also, in 17.4.8, another example states:
Since the reads come first in each thread, the very first action in the execution order must be a read. If that read cannot see a write that occurs later, then it cannot see any value other than the initial value for the variable it reads.
(Emphasis mine again). Note that this, though it's in an example and not in the "main" body, explicitly says that junk reads as you describe is not allowed.
And then, JLS 17.7 is all about the non-atomicity of 64 bit primitives (the long and double values I mentioned above). Again, if there were absolutely no guarantees about the bytes you see, then it wouldn't be meaningful to note that you can see one word from one write and another word from another write. In other words, the fact that the JLS says that you can see "broken" values that arise from only one word being updated, is a strong suggestion that you can't see "broken" values that arise from just complete left-over junk.
Java has no access to the underlying hardware cache, so it does not "ensure the clearing of every processsor's cache".
Most modern, real CPUs provide for cache coherency. Some real CPUs require a memory barrier under some circumstances. Your hypothetical CPU without a hardware mechanism will likely suffer from a stale cache under the conditions described.
As long as the accesses to fooRef and fooRef.x are properly synchronized, thread T2 will see the latest value of fooRef.x, i.e., 10.

Assigning "null" to objects in every application after their use

Do you always assign null to an object after its scope has been reached?
Or do you rely on the JVM for garbage collection?
Do you do it for all sort of applications regardless of their length?
If so, is it always a good practice?
It's not necessary to explicitly mark objects as null unless you have a very specific reason. Furthermore, I've never seen an application that marks all objects as null when they are no longer needed. The main benefit of garbage collection is the intrinsic memory management.
no, don't do that, except for specific cases such as static fields or when you know a variable/field lives a lot longer than the code referencing it
yes, but with a working knowledge of your VM's limits (and how to cause blocks of memory to be held accidentally)
n/a
I declare almost all of my variables as "final". I also make my methods small and declare most variables local to methods.
Since they are final I cannot assign them null after use... but that is fine since the methods are small the objects are eligible for garbage collection once they return. Since most of the variables are local there is less chance of accidentally holding onto a reference for longer than needed (memory leak).
Assignin null to a variable does not implicitly mean it will be garbage collected right away. In fact it most likely won't be. Whether you practice setting variables to null is usually only cosmetic (with the exception of static variables)
We don't practice this assigning "null". If a variable's scope has reached it's end it should already be ready for GC. There may be some edge cases in which the scope lasts for a while longer due to a long running operation in which case it might make sense to set it to null, but I would imagine they would be rare.
It also goes without saying that if the variable is an object's member variable or a static variable and hence never really goes out of scope then setting it to null to GC is mandatory.
Garbage collection is not as magical as you might expect. As long as an object is referenced from any reachable object it simply can't be collected. So it might be absolutely necessary to null a reference in order to avoid memory leaks. I don't say you should do this always, but always when it's necessary.
As the others have mentioned, it's not usually necessary.
Not only that, but it clutters up your code and increases the data someone needs to read and understand when revisiting your code.
Assigning is not done to objects, it is done to variables, and it means that this variable then holds a reference to some object. Assigning NULL to a variable is not a way to destroy an object, it just clears one reference. If the variable you are clearing will leave its scope afterwards anyway, assigning NULL is just useless noise, because that happens on leaving scope in any case.
The one time I tend to use this practice is if I need to transform a large Collection in some early part of a method.
For example:
public void foo() {
List<? extends Trade> trades = loadTrades();
Map<Date, List<? extends Trade>> tradesByDate = groupTradesByDate(trades);
trades = null; // trades no longer required.
// Apply business logic to tradesByDate map.
}
Obviously I could reduce the need for this by refactoring this into another method: Map<Date, List<? extends Trade>>> loadTradesAndGroupByDate() so it really depends on circumstances / clarity of code.
I only assign a reference to null when:
The code really lies in a memory-critical part.
The reference has a wide scope (and must be reused later). If it is not the case I just declare it in the smallest possible code block. It will be available for collection automatically.
That means that I only use this technique in iterative process where I use the reference to store incoming huge collection of objects. After processing, I do not need the collection any more but I want to reuse the reference for the next collection.
In that case (and only in that case), I then call System.gc() to give a hint to the Garbage Collector. I monitored this technique through heap visualizer and it works very well for big collections (more then 500Mb of data).
When using the .Net I don't think there's a need to set the object to null. Just let the garbage collection happen.
- Do you always assign null to an object after its scope has been reached?
No
- Or do you rely on the JVM for garbage collection?
Yes
- Do you do it for all sort of applications regardless of their length?
Yes
- If so, is it always a good practice?
N/A
I assume you're asking this question because you've seen code with variables being assigned to null at the point where they will never be accessed again.
I dislike this style, but another programmer used it extensively, and said he was taught to do so at a programming course at his university. The reasoning he gave is that it would prevent undetectable bugs if he tried to reuse the variable later on, instead of indeterminate behavior, he'd get a null pointer exception.
So if you're prone to using variables where you shouldn't be using variables, it might make your code more easy to debug.
There was a class of memory leak bugs that happened regardless of whether I set the reference to null - if the library I was using was written in a language like C without memory management, then simply setting the object to null would not necessarily free the memory. We had to call the object's close() method to release the memory (which, of course, we couldn't do after setting it to null.)
It thus seems to me that the de facto method of memory management in java is to rely on the garbage collector unless the object/library you're using has a close() method (or something similar.)

Categories