我目前正在看一段关于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字节。
我是不是漏掉了什么?
发布于 2014-06-20 23:17:46
这可能是过于简化,但它会给你基本的想法。
下面是一个测试类,它将方法与额外引用进行比较,而等效方法与内联调用进行比较:
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
如果仔细观察,唯一的区别是字节码中有一个额外的引用存储/加载指令。
现在,如果这段代码是按原样执行的,您可能会注意到在大量调用之后(例如在循环中)的不同。额外的CPU周期可能会被烧毁,您必须使用堆栈上的一个位置来存储引用(这根本不应该困扰GC,因为GC只处理堆,堆栈上的项将自动从this应答中释放出来)。但我不认为这是很大的代价。
然而,在几乎每个JVM上都有一个称为JIT编译器的神奇实体(以及Android使用的Dalvik VM,如果内存正常的话)。JIT编译器能够内联额外的引用,因此具有额外引用的代码本质上与没有额外引用的代码完全相同。对于JIT编译器来说,这应该是一个相对容易执行的优化,特别是对于更现代的VM。
因此,最后,如果有任何不同,您可以安全地忽略它,因为JITC。在这种情况下,您应该选择更具可读性的代码样式。
发布于 2014-06-20 21:31:35
在视频中,他提到删除对象的引用,从
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());
}
无论如何,我认为他的意思是(我不能肯定)这是对可读性的改进,因为内存将在创建对象时消耗,而不是在变量分配上使用。
发布于 2014-06-20 21:22:22
随着这种改变,代码看起来更“优化”一些,但不,它不会显着地减少内存使用。
https://stackoverflow.com/questions/24335782
复制相似问题