最近我看到一篇关于Android内存优化的文章,但我认为我的问题更多的是一般的Java类型。我找不到任何这方面的信息,所以如果您能为我指出一个好的资源来阅读,我将不胜感激。
我说的这篇文章可以找到here .
我的问题涉及以下两个 fragment :
非最佳版本:
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());
}
本文还包含以下几行(与第一个 fragment 相关):
In the second loop of the code snippet above, we are creating a new chunk object for each iteration of the loop. So it will essentially create 10,000 objects of type ‘Chunk’ and occupy a lot of memory.
我努力理解的是为什么提到新对象的创建,因为我只能看到对堆上已经存在的对象的引用的创建。我知道引用本身会花费 4-8 个字节,具体取决于系统,但在这种情况下它们很快就会超出范围,除此之外我没有看到任何额外的开销。
也许创建对现有对象的引用在数量众多时被认为是昂贵的?
请告诉我我在这里错过了什么,以及两个 fragment 在内存消耗方面的真正区别是什么。
谢谢。
最佳答案
有两个区别:
非最佳:
-
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()
的人没有开销,我只能引用官方文档:
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? .
关于java - Java/Android 中现有对象的短期引用的开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29421287/