我目前正在观看有关Android代码优化的视频(https://www.youtube.com/watch?v=w9taB0yUwjs)
在本视频中,他正在优化以下代码:
List<Contact> contacts = new ArrayList<Contact>();
if (cursor.moveToFirst()) {
do {
Contact contact = new Contact(...);
contacts.add(contact);
while(cursor.moveToNext());
}
他建议以下内容可以释放记忆。
List<Contact> contacts = new ArrayList<Contact>();
if (cursor.moveToFirst()) {
do {
contacts.add(new Contact(...));
while(cursor.moveToNext());
}
我不太明白为什么这会释放内存。我的(有限的)理解是contact
变量只是存储在堆栈中的对象引用。匿名创建对象实际上会显着减少内存使用量吗?从阅读this answer开始,对象引用似乎仅占用4到8个字节。
我在这里错过了什么吗?
答案 0 :(得分:4)
这可能过于简单,但它会给你基本的想法。
这是一个测试类,将方法与额外引用进行比较,将等效方法与内联调用进行比较:
public class Test {
static List<String> list = new ArrayList<>();
public static void extraReference() {
String s = new String();
list.add(s);
}
public static void noReference() {
list.add(new String());
}
}
这是方法的字节码,与声明的顺序相同:
public static void extraReference();
Code:
0: new #2 // class java/lang/String
3: dup
4: invokespecial #3 // Method java/lang/String."<init>":()V
7: astore_0
8: getstatic #4 // Field list:Ljava/util/List;
11: aload_0
12: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
17: pop
18: return
public static void noReference();
Code:
0: getstatic #4 // Field list:Ljava/util/List;
3: new #2 // class java/lang/String
6: dup
7: invokespecial #3 // Method java/lang/String."<init>":()V
10: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
15: pop
16: return
如果仔细观察, only 区别是字节码中的额外参考存储/加载指令。
现在,如果此代码按原样执行,您可能会在很多调用之后发现差异 - 例如在循环中。额外的CPU周期可能会被烧毁,你必须在堆栈上使用一个位置来存储引用(因为GC只处理堆,所以不应该打扰GC,并且堆栈中的项自动释放,来自this回答)。但我不会将费用称为重要。
然而,几乎每个JVM(以及Android使用的Dalvik VM,如果内存服务)都有称为JIT编译器的神奇实体。 JIT编译器能够内联额外的引用,因此带有额外引用的代码基本上与没有额外引用的代码完全相同。这应该是JIT编译器执行的相对简单的优化,尤其是对于更现代的VM。
所以最后,如果存在差异,你可以放心地忽略它,因为JITC。在这种情况下,您应该选择更易读的代码样式。
答案 1 :(得分:1)
在视频中,他提到摆脱对象的引用,从
改变if (cursor.moveToFirst()) {
do {
Contact contact = new Contact(...);
contacts.add(contact);
while(cursor.moveToNext());
}
到
Contact contact = null;
if (cursor.moveToFirst()) {
do {
contact = new Contact(...);
contacts.add(contact);
while(cursor.moveToNext());
}
然后到
if (cursor.moveToFirst()) {
do {
contacts.add(new Contact(...));
while(cursor.moveToNext());
}
在任何情况下,我认为他的意思是(我不能确定)这是对可读性的改进,因为内存会在创建对象时消耗,而不是在变量分配上消耗。
答案 2 :(得分:0)
通过这种更改,代码对某些代码看起来更“优化”,但不会显着减少内存使用量。
答案 3 :(得分:0)
优化也可能发生在编译器端,这不是通过读取代码揭示的。 这里的任何形式的代码都不会改变对象的生命周期,所以对我来说没有优化,只需要更少的代码。