引用一个对象是否会导致内存使用不同 [英] Does referring to an object makes different in memory usage

查看:28
本文介绍了引用一个对象是否会导致内存使用不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我有这两个代码:

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


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

在第一个代码中,我创建了两个对象并保存,因此程序需要两个对象的内存.
但是在第二个代码中,我从 A 创建了对象并且我没有将它保存在任何变量中,所以我的问题是:
这两个代码有什么不同?是语法还是对内存有影响?

解决方案

引用/指针与对象

您的术语已保存"没有技术意义,可能会让您感到困惑.

让我们更具体一点.将 A 类替换为 Cat 类.将 B 类替换为 Breed 类.

假设在实例化 Cat 时,我们还实例化了一个 Breed 对象,该对象包含在该 Cat 对象中.换句话说,我们在此

请注意,访问Breed 对象的唯一方法是通过Cat 对象Fluffy.我们的代码可以访问该Cat 对象的唯一方法是通过名为a 的引用/指针变量.

Breed b = a.getBreed() ;//访问 `Cat` 实例,然后遍历到 `Breed` 对象.

在那段代码之后,我们现在分配了一点内存来保存另一个指针/引用,名为 b 的变量.b 变量不是 Cat 也不是 Breed,它是找到 Breed 对象的内存位置记忆中的别处.我们现在可以直接访问 Breed 对象,而无需通过 Cat 实例.

概念图:

一行

您的其他代码:

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

...转换为我们的示例:

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

... 非常相似,但从未将引用 a 建立为命名变量.引用 至少在概念上是生成的(实际上,JVM 可能有优化).简短的临时引用用于立即调用 getBreed 方法.

获得Breed对象的内存位置后,释放对新Cat对象的临时引用,新Cat对象超出范围.从技术上讲,新的 Cat 对象可能仍会在内存中漂浮片刻,成为

至于内存管理,在您的两种场景中可能会占用相同数量的内存(取决于您的 JVM 实现).这两种情况都在建立一对对象和一对引用.一个细微的区别是,在您的第二个场景中,Cat 对象及其临时指针立即超出范围,并成为垃圾收集的候选对象.因此,内存可能比您的第一个场景更快地回收.在实践中,差异可能微不足道.

不要微优化

正如其他人评论的那样,所有这些都只是学术性的.您通常不必担心此类微优化.

现代编译器和 JVM 都经过了极好的优化,是有史以来优化和测试最完善的大型软件项目.因此,编写 Java 代码的最佳方式就是简单.为人类编写简单易读且易于理解的代码,您还将编写最有可能被编译器和 JVM 优化的代码.试图通过超越编译器的思考变得聪明 &具有讽刺意味的是,JVM 很可能会适得其反,从而导致代码的优化程度较低.


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?

解决方案

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.

这篇关于引用一个对象是否会导致内存使用不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆