7

You create a variable to store a value that you can refer to that variable in the future. I've heard that you must set a variable to 'null' once you're done using it so the garbage collector can get to it (if it's a field var).

If I were to have a variable that I won't be referring to agaon, would removing the reference/value vars I'm using (and just using the numbers when needed) save memory? For example:

int number = 5;
public void method() {
    System.out.println(number);
}

Would that take more space than just plugging '5' into the println method?

I have a few integers that I don't refer to in my code ever again (game loop), but I've seen others use reference vars on things that really didn't need them. Been looking into memory management, so please let me know, along with any other advice you have to offer about managing memory

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
Vince
  • 14,470
  • 7
  • 39
  • 84
  • Why not just test both programs and compare computational times? See [this](http://stackoverflow.com/questions/5204051/how-to-calculate-the-running-time-of-my-program). – Tdorno Dec 31 '13 at 23:00
  • 1
    Note that `number`, in your case, is *not* a reference variable: it's a primitive `int`, so it's a value variable. (References have object types; for example, `Integer number` would create a reference.) – ruakh Dec 31 '13 at 23:00
  • You don't need to explicitly set variables to `null` when you're "done" with them. That advice applies only to the specific case of array elements, to keep you from inadvertently hanging on to objects you don't need anymore. As references go out of scope, they automatically get discarded. – chrylis -cautiouslyoptimistic- Dec 31 '13 at 23:03
  • Don't forget that premature optimization is the root of all evil. If it's a couple integers (4-8 bytes each), would it really matter when other parts of the program may be using megabytes of memory? Also, the compiler's pretty smart and may actually compile out some of the integers without you needing to tell it to. – cactus1 Dec 31 '13 at 23:04

5 Answers5

5

I've heard that you must set a variable to 'null' once you're done using it so the garbage collector can get to it (if it's a field var).

This is very rarely a good idea. You only need to do this if the variable is a reference to an object which is going to live much longer than the object it refers to.

Say you have an instance of Class A and it has a reference to an instance of Class B. Class B is very large and you don't need it for very long (a pretty rare situation) You might null out the reference to class B to allow it to be collected.

A better way to handle objects which don't live very long is to hold them in local variables. These are naturally cleaned up when they drop out of scope.

If I were to have a variable that I won't be referring to agaon, would removing the reference vars I'm using (and just using the numbers when needed) save memory?

You don't free the memory for a primitive until the object which contains it is cleaned up by the GC.

Would that take more space than just plugging '5' into the println method?

The JIT is smart enough to turn fields which don't change into constants.

Been looking into memory management, so please let me know, along with any other advice you have to offer about managing memory

Use a memory profiler instead of chasing down 4 bytes of memory. Something like 4 million bytes might be worth chasing if you have a smart phone. If you have a PC, I wouldn't both with 4 million bytes.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Re: "if the variable is a reference to an object which is going to live much longer than the object it refers to": I think you must have a typo here somewhere, or something. – ruakh Jan 01 '14 at 00:34
  • I understand him, I think. If the var changes what it's referring to, it'll live longer than the object, right? And when you say the object a primitive is stored in, what object do you mean? – Vince Jan 01 '14 at 01:08
  • primitives only exist on the stack or inside an object. This means there is always an object on the heap it must be stored in (or it is just a local variable and doesn't use any heap) I have added an example to clarify what I mean. – Peter Lawrey Jan 01 '14 at 09:52
1

In your example number is a primitive, so will be stored as a value.

If you want to use a reference then you should use one of the wrapper types (e.g. Integer)

djhworld
  • 6,726
  • 4
  • 30
  • 44
0

So notice variables are on the stack, the values they refer to are on the heap. So having variables is not too bad but yes they do create references to other entities. However in the simple case you describe it's not really any consequence. If it is never read again and within a contained scope, the compiler will probably strip it out before runtime. Even if it didn't the garbage collector will be able to safely remove it after the stack squashes. If you are running into issues where you have too many stack variables, it's usually because you have really deep stacks. The amount of stack space needed per thread is a better place to adjust than to make your code unreadable. The setting to null is also no longer needed

Greg Giacovelli
  • 10,164
  • 2
  • 47
  • 64
0

It's really a matter of opinion. In your example, System.out.println(5) would be slightly more efficient, as you only refer to the number once and never change it. As was said in a comment, int is a primitive type and not a reference - thus it doesn't take up much space. However, you might want to set actual reference variables to null only if they are used in a very complicated method. All local reference variables are garbage collected when the method they are declared in returns.

Epiglottal Axolotl
  • 1,048
  • 8
  • 17
0

Well, the JVM memory model works something like this: values are stored on one pile of memory stack and objects are stored on another pile of memory called the heap. The garbage collector looks for garbage by looking at a list of objects you've made and seeing which ones aren't pointed at by anything. This is where setting an object to null comes in; all nonprimitive (think of classes) variables are really references that point to the object on the stack, so by setting the reference you have to null the garbage collector can see that there's nothing else pointing at the object and it can decide to garbage collect it. All Java objects are stored on the heap so they can be seen and collected by the garbage collector.

Nonprimitive (ints, chars, doubles, those sort of things) values, however, aren't stored on the heap. They're created and stored temporarily as they're needed and there's not much you can do there, but thankfully the compilers nowadays are really efficient and will avoid needed to store them on the JVM stack unless they absolutely need to.

On a bytecode level, that's basically how it works. The JVM is based on a stack-based machine, with a couple instructions to create allocate objects on the heap as well, and a ton of instructions to manipulate, push and pop values, off the stack. Local variables are stored on the stack, allocated variables on the heap.* These are the heap and the stack I'm referring to above. Here's a pretty good starting point if you want to get into the nitty gritty details.

In the resulting compiled code, there's a bit of leeway in terms of implementing the heap and stack. Allocation's implemented as allocation, there's really not a way around doing so. Thus the virtual machine heap becomes an actual heap, and allocations in the bytecode are allocations in actual memory. But you can get around using a stack to some extent, since instead of storing the values on a stack (and accessing a ton of memory), you can stored them on registers on the CPU which can be up to a hundred times (maybe even a thousand) faster than storing it on memory. But there's cases where this isn't possible (look up register spilling for one example of when this may happen), and using a stack to implement a stack kind of makes a lot of sense.

And quite frankly in your case a few integers probably won't matter. The compiler will probably optimize them out by itself in this case anyways. Optimization should always happen after you get it running and notice it's a tad slower than you'd prefer it to be. Worry about making simple, elegant, working code first then later make it fast (and hopefully) simple, elegant, working code.

Java's actually very nicely made so that you shouldn't have to worry about nulling variables very often. Whenever you stop needing to use something, it will usually incidentally be disappearing from the scope of your program (and thus becoming eligible for garbage collection). So I guess the real lesson here is to use local variables as often as you can.

*There's also a constant pool, a local variable pool, and a couple other things in memory but you have close to no control over the size of those things and I want to keep this fairly simple.

cactus1
  • 629
  • 5
  • 8
  • Nicely explained :) a few questions: from what I've learned so far, there are 2 heaps (java and native), yeah? Do objects get stored in the Java heap or native? And I'm assuming values are stored in opposite, right? Also, when you say temporarily stored, where is it stored if it's not the heap? – Vince Jan 01 '14 at 01:02
  • Added another paragraph above :). But basically, kind of, heap, yes, and the stack. Values are pushed and popped off the stack in [first in first out](http://en.wikipedia.org/wiki/FIFO) order in the stack, which is why it's called the stack, but objects are allocated and deallocated in a less ordered way. Something you made recently may be garbage collected sooner than something you made a while ago, but values stored on the stack have to be added and removed with almost ritualistic precision. – cactus1 Jan 01 '14 at 01:27
  • [last in first out](http://en.wikipedia.org/wiki/LIFO_%28computing%29), I meant :/. – cactus1 Jan 01 '14 at 01:46
  • @VinceEmigh The heap is in native space, all Objects exist in the heap, nowhere else. – Peter Lawrey Jan 01 '14 at 09:54