从哪些情况导致内存溢出说起
说到Android的内存溢出,一般人都会说到以下几点
- 内存泄漏
- 不用的图片没有GC
- 大图加载
- 加载大量的图片
- 创建大量的线程
- …
那么真的是这样吗?是不是我不加载大图就不会内存溢出?是不是我不加载大量图片就不会内存溢出?不创建大量线程就不会内存溢出?…
答案是否定的。
不信你试试下面这个代码。
List<String> list = new ArrayList<>();
private void doTest() {
for (int i=0;;i++){
Log.e("TAG", "doTest: "+i );
list.add(i+"");
}
}
楼主的小米8 内存会一直暴涨到1g多,然后虽然没有崩溃,但是log里会输出。
2019-12-30 19:03:51.576 30046-30057/com.lzp.appexp E/System: Uncaught exception thrown by finalizer
2019-12-30 19:04:37.275 30046-30057/com.lzp.appexp E/System: java.lang.OutOfMemoryError: Failed to allocate a 8 byte allocation with 0 free bytes and 0B until OOM, max allowed footprint 536870912, growth limit 536870912
很明显我也没有创建大图,甚至都没有加载图片。也没有创建线程。
我们再来分析下为什么会发生这种情况。
看过内存JVM回收机制和内存回收算法发应该都知道,JVM所管理的内存主要包括以下几个运行时数据区域:方法区,本地方法区,堆,虚拟机栈,程序计数器。其中,程序计数器,虚拟机栈,本地方法区都是随性线程而生,随线程而灭的。堆和方法区会使用可达性分析,计数法等等算法,进行垃圾回收。显然例子的每个字符串都不能回收。那么内存也就会持续增加。直到oom。
再问哪些情况会导致内存溢出
再来看看题目开始的问题,哪些情况会导致内存溢出呢?
显然答案是任何对象的创建都有可能导致内存溢出。但是有几个场景会加大内存溢出的概率。比如:
- 内存泄漏
- 不用的图片没有GC
- 大图加载
- 加载大量的图片
- 创建大量的线程
- …
就是开头我们提到的那些了。
我们该怎么避免内存溢出
既然知道了什么情况会产生内存溢出。要解决也就不难了。总结如下
- 创建对象的时候,不要创建大对象。比如创建bitmap的时候指定宽高,可以大幅度减少内存的消耗。
- 创建了大对象要及时回收。或者大对象标记为可以被回收的,比如软引用,虚引用,弱引用等等。
- 创建对象的时候考虑下回收时机。比如能在局部变量,不声明成员变量,能成员不静态。这样就能减少GC的次数。
- 避免频繁的创建对象,比如在for循环里,onDraw里,创建对象。会被频繁的调用,容易内存抖动。
- …(你来补充)