泄漏 memory leak 是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,
但内存泄漏堆积后, 会变得很严重,无论有多少空间,迟早会被占光。
memory leak 最终会导致 OOM (out of memory)。 看一个图
一. 溢出 out of memory 是指程序在申请内存空间时, 没有足够的空间供其使用,出现OOM, 比如申请了1M的图片空间,但它要存一个5M大小的图片,就是内存溢出。
分析: 垃圾回收就是一种自动在堆内存中找出哪些对象在被使用, 哪些对象没被使用,并且将没被使用的删掉的机制。
注意:JVM有GC机制, C++才需要手动回收。
二. 接下来了解 内存抖动
短时间内有大量对象创建销毁导致,它会伴随着频繁的GC.
我们在AS上运行Android工程时,点击Profile 'app' 按钮,可以看到很多系统配置信息
, 点击后,可看到下方如图所示
,
内存抖动可以用 如下图所示: 图表跳动很强烈
2.1 内存抖动的影响: 卡顿
2.2 内存抖动的影响:OOM
应用的GC运行时,会将程序所有线程挂起,因为一边在回收垃圾,一边在产生垃圾, 会导致回收还没有产生快,垃圾越来越多。
看一个图,形象表示内存使用情况:
2.3 内存抖动 的原因有:
1. 字符串的拼接, 例如
for(int i=0;i<values.length;i++){
/**
* 使用+号, 看起来是修改了值,其实是把变量指向的内存区域,指向的对象发生了变化
* 而对于字符串本身是不变的, +号是做了StringBuilder()的append()方法
*/
result +=values[i];
//以下写法与 上句效果相同, 但是会创建大量临时对象
//result = new StringBuilder().append(result).append(values[i]).toString();
// 第三步,通过javap -c com.rd.memory.TestMemory 命令行来查看class文件的指令
}
2. 有的方法会创建新的对象,例如 Color.parseColor()方法, 会创建一个新的String对象。
此方法 如果是放在循环调用里(如onDraw()),将导致产生很多String对象。
解决方法: 用 paint.setColor(colorInts[i]) 代替 paint.setColor(Color.parseColor(color[i])),
也就是说传递 int类型数组的参数, 不是字符串数组再转化的参数。
3. 内存抖动的根本原因是 创建大量的临时对象, 这些对象用完一次就不要了, 最常见是在 for循环中 创建String对象。
不是说创建大量对象就一定会内存抖动。
4. 看一个例子,
public class TestMemory {
public static void main(String[] args) {
addStr(new String[]{"cpu", "memory", "network"});
}
public static String addStr(String[] values){
//字符串定义了值,是不可变的
String result = "";
for(int i=0;i<values.length;i++){
/**
* 使用+号, 看起来是修改了值,其实是把变量指向的内存区域,指向的对象发生了变化
* 而对于字符串本身是不变的, +号是做了StringBuilder()的append()方法
*/
result +=values[i];
//以下写法与 上句效果相同, 但是会创建大量临时对象
//result = new StringBuilder().append(result).append(values[i]).toString();
// 第三步,通过javap -c com.rd.memory.TestMemory 命令行来查看class文件的指令
}
return result;
}
}
用 javap 执行如下命令,可以看到TestMemory执行的指令过程
在profile界面中, 点击Record按钮,开始记录一段时间应用的内存情况
内存泄漏是造成内存溢出的主要原因之一。