Memory-management in java

2019-09-21 21:49发布

问题:


I have this two codes:

A a = new A();
B b = a.getB();


B b = new A().getB();

In the first code I created two objects and saved them so the program need memory for two objects
but in the second code I created object from A and I didn't saved it in any variable so my question is :
what is the different between this two codes? is it just a syntax or there is an effect on memory?

回答1:

Reference/Pointer versus Object

Your term "saved" has no technical meaning, and may be confusing you.

Let’s get more concrete. Replace A class with Cat class. Replace B class with Breed class.

Let's assume that when instantiating a Cat we also instantiate a Breed object held within that Cat object. In other words, we are not doing lazy-loading in this example. So when instantiating a Cat, we pass along an instance of Breed to the constructor.

Two lines

The Cat a variable does not hold a Cat object, it holds a reference (a pointer) to the Cat object that was constructed elsewhere in memory. That location of the Cat object in memory, basically a number, is what is held by the Cat a.

Cat a = new Cat( "Fluffy" , new Breed( "Tabby" ) ) ;  Passing new instance of `Breed` to constructor of `Cat`, with resulting `Cat` object’s location in memory being returned to the `a` reference/pointer variable.

You can think of that line of code as this:

Pointer-holding-memory-location-of-object-of-class-Cat a = Instantiate-a-new-Cat-object-somewhere-in-memory-and-return-its-memory-location( … ) ;

Conceptual diagram:

Notice that the only way to access the Breed object is to go through the Cat object Fluffy. The only way our code can get to that Cat object is through the reference/pointer variable named a.

Breed b = a.getBreed() ;  // Accessing the `Cat` instance, then traversing to the `Breed` object.

After that code we have wee bit of memory now allocated to holding another pointer/reference, the variable named b. The b variable is not Cat nor a Breed, it is the memory location of where to find the Breed object elsewhere in memory. We can now directly access the Breed object, without going through the Cat instance.

Conceptual diagram:

One line

Your other code:

B b = new A().getB() ;

…converted to our example:

Breed b = new Cat( "Fluffy" , new Breed( "Tabby" ) ).getBreed() ;

…is quite similar, but never establishes the reference a as a named variable. The reference is generated, at least conceptually (in actuality a JVM may have optimizations). The brief ephemeral reference is used to immediately call the getBreed method.

After obtaining a memory-location of the Breed object, the ephemeral reference to the new Cat object is released, and the new Cat object falls out of scope. The new Cat object technically is likely still floating in memory for a moment, becoming a candidate for garbage-collection, due to be purged from memory.

Of course the new one-liner seen above using Cat and Breed becomes silly: We instantiate a new Breed, pass it to the constructor of Cat, and then immediately ask to get it back. Let’s ignore the awkward silliness for the sake of this memory-management discussion.

Conceptual diagram:

As for memory management, the same amount of memory is likely taken in both your scenarios (depending on your JVM implementation). Both scenarios are establishing a pair of objects and a pair of references. The one slight difference is that in your second scenario the Cat object and its ephemeral pointer go out of scope immediately, and become candidates for garbage-collection. So memory might be reclaimed sooner than in your first scenario. In practice, the difference would likely be insignificant.

Do not micro-optimize

As others commented, all this is merely academic. You generally should not worry about such micro-optimizations.

The modern compilers and JVMs are extremely well-optimized, some of the most well-optimized and well-tested large software projects ever. So the best way to write Java code is simply. Write simple easy-to-read and easy-to-understand code for humans, and you will also be writing code that is most likely to be well-optimized by the compiler and JVM. Trying to be clever by out-thinking the compiler & JVM is ironically liable to be counter-productive, resulting is less-optimized code.



回答2:

For light objects, very few differences.
In the first code the A object is assigned to a variable. So it is eligible to be garbage collected only as the variable is out of the scope.
In the second code the A object is not assigned to a variable. So it is right now eligible to be garbage collected.
In a general way you should not worry about this kind of things and using a variable or not using it only if it makes sense.



回答3:

You kinda answered your own question. In the first example, you created two variables 'A' and 'B' so more memory is used. In the second example, you only created on variable B, so less memory is used. In the second example, a new 'A' is created then the newly object calls the method getB() and the result is stored in the variable 'B'. In this situation the memory difference is very minimal, but if this was repeated multiple times over the course of a program then the memory usage could stack up.

Also, Java has its own garbage collector and when it runs it collects/deleted the memory of the objects that are no longer accessible. Once a variable goes out of scope, then the garbage collection can run and clean up that unused memory. With the garage collector in place, the memory difference in the two statements almost does not matter.