内存抖动
在一定时间内,内存频繁地分配和回收。用图像展示就如下图(网上找的图片,侵删),内存急剧上升之后又急剧下降。
内存抖动的原因:Java的垃圾回收机制,一个对象不用的时候会被系统回收。在实际的场景中能就例如在一个方法里面创建了很多局部对象,这些对象因为作用域只在方法里面,所以在方法结束之后会被垃圾回收线程回收。 垃圾回收看这里
内存抖动会引发的问题:
- 卡顿:对象回收的时候会暂停其它线程,执行垃圾回收,虽然垃圾回收执行的时间很短,但是也是会耗时间的,如果频繁进行垃圾回收就会频繁暂停UI线程。反映到用户层面呢,就是界面有点卡顿,因为UI线程被暂停了嘛。例如Android中就建议不要在onDraw方法中创建对象。
- OOM:频繁创建回收有可能导致内存可用空间不连续,每一个可用的连续空间不足以容纳新创建的对象。(这个发生的情况比较少,因为一般会频繁创建回收的对象都是发生在年轻代的,年轻代一般会采用复制算法来保证可用空间的连续。但是假如你每次创建的对象特别大,大到直接分配在老年代内存中,那么根据老年代采用的垃圾回收算法,是有可能会造成内存不连续的,例如采用了标记-清除算法)
内存抖动的代码示例
private String test(){
String s = "";
for (int i = 0; i < 1000; i++) {
s+=i;
}
return s;
}
相信很多人写过这样的代码,那么这代码有没有问题呢?我们看一下字节码
LINENUMBER 7 L4
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ILOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
上面这一段对于s+=i
这一行代码,从字节码可以看出,每次都是new一个StringBuilder
对象然后再调用append
方法将i加到后面,然后再调用toString
将值赋值给s。也就是说这个for循环会有StringBuilder
对象的频繁创建和销毁。
优化
private String test(){
StringBuilder s = new StringBuilder();
for (int i = 0; i < 1000; i++) {
s.append(i);
}
return s.toString();
}
将代码改成如上所示,将StringBuilder提取出来,在for里面执行append方法即可。
最近为了督促自己学习,搞了个公众号,算是自己平时的学习笔记,以后面试的时候看一看。有兴趣的可以微信搜索序员说公众号,每天花五分钟跟我一起学习,或者发送消息分享下工作、生活的事情也行。