Java / Android中对现有对象的短暂引用的开销

时间:2015-04-02 19:49:59

标签: java android performance memory-management

最近我发现了一篇关于Android内存优化的文章,但我认为我的问题更多的是一般的Java类型。我无法找到关于此的任何信息,所以如果你能给我一个很好的阅读资源,我将不胜感激。

我可以找到我正在谈论的文章here

我的问题涉及以下两个片段:

非最佳版本:

List<Chunk> mTempChunks = new ArrayList<Chunk>();
for (int i = 0; i<10000; i++){
    mTempChunks.add(new Chunk(i));
}

for (int i = 0; i<mTempChunks.size(); i++){
    Chunk c = mTempChunks.get(i);
    Log.d(TAG,"Chunk data: " + c.getValue());
}

优化版本:

Chunk c;
int length = mTempChunks.size();
for (int i = 0; i<length; i++){
    c = mTempChunks.get(i);
    Log.d(TAG,"Chunk data: " + c.getValue());
}

该文章还包含以下几行(与第一个代码段相关):

  

在上面代码片段的第二个循环中,我们为循环的每次迭代创建一个新的块对象。因此,它实际上将创建10,000个“Chunk”类型的对象并占用大量内存。

我努力理解的是为什么要提到新的对象,因为我只能看到在堆上创建对已存在的对象的引用。我知道一个引用本身需要4-8个字节,具体取决于系统,但在这种情况下它们会很快超出范围,除此之外我不会看到任何额外的开销。

也许它创建了对现有对象的引用,这种对象在众多时被认为是昂贵的?

请告诉我我在这里错过了什么,以及两个片段在内存消耗方面的真正区别。

谢谢。

1 个答案:

答案 0 :(得分:2)

有两点不同:

非最佳:

  • i < mTempChunks.size()
  • Chunk c = mTempChunks.get(i);

最优:

  • i < length
  • c = mTempChunks.get(i);

在非最佳代码中,为循环的每次迭代调用size()方法,并创建到Chunk对象的新引用。在最佳代码中,避免了重复调用size()的开销,并且相同的引用被回收。

然而,该文章的作者似乎错误地建议在第二个非最佳循环中创建10000个临时对象。当然,创建了10000个临时对象 ,但是在第一个,而不是第二个循环中,并且没有办法避免这种情况。在第二个非最优循环中,创建了10000个引用。所以在某种程度上它不是最优的,尽管作者错误地为森林树木。

进一步参考:

1。 Avoid Creating Unnecessary Objects

2。 Use Enhanced For Loop Syntax

修改

我被指控为骗子。对于那些说调用size() no 开销的人,我只能引用官方文档

3。 Avoid Internal Getters/Setters

编辑2:

在我的回答中,我最初错误地说,内存用于引用是在编译时在堆栈上分配的。我现在意识到这种说法是错误的;这实际上是C ++中的工作方式,而不是Java。 Java的世界是颠倒的C ++:引用的内存确实在堆栈中分配,在Java中甚至在运行时发生。心灵爆炸!

<强>参考文献:

1。 Runtime vs compile time memory allocation in java

2。 Where is allocated variable reference, in stack or in the heap?

3。 The Structure of the Java Virtual Machine - Frames