做Android开发其实经常会遇到OOM然后程序崩溃的情况,导致这种情况一般来说是内存泄露造成的,捕获内存泄露的工具是leakCanary2还是推荐一下,当然本章并不是说这个的使用方法,程序OOM时会造成直接崩溃,在使用中会影响用户体验,这里就说一下实现OOM的捕获的方法。
实现效果
将try catch(e:Exception)改为try catch(e:Throwable)即可实现捕获OOM
为什么改为Throwable后就能捕获OOM了呢?那我们做个小小的Demo来测试一下。
任何一个Project中新一个文件,我这起名为Test
为了程序运行中能够更快的出现OOM,要改一下配置,主要就是把JVM的内存堆分配的小一点,
2.将刚才创建的Test.kt的文件中VM options项里填上-Xms20m -Xmx20m
参数项的说明:
package pers.vaccae.draganddropdemo
fun main(){
class oomobj{
var testno =1
var testname ="11234"
}
val list = mutableListOf<oomobj>()
try {
while (true){
list.add(oomobj())
}
} catch (e: Exception) {
print(e.message.toString())
}
}
从上面代码中可以看到,有个oomobj的类,然后通过while的死循环不停的在集合中插入新的oomobj这个类,用try catch(e:Exception)进行捕获,得到下图:
可以看到,提了OutOfMemoryError,那我们点一下OutOfMemoryError这里
可以看出来OutOfMemoryError继承自VirtualMachineError类。那为什么Exception捕获不到呢?接下来再看一个图:
从上图中可以看出来,OutOfMemory继承的VirtualMachineError是Error的分支里,而我们用Exception中是无法捕获的,想到获取到Error的信息,可以从它们的父类Throwable中获取,接下来我们改一下代码,将Exception改为Throwable
改完后可以正常打印Throwable的输出结果
虽然我们捕获了OOM,但如果内存就是溢出后,那程序是否还能运行了呢?那我们改一下代码再看看
package pers.vaccae.draganddropdemo
fun main(){
class oomobj{
var testno =1
var testname ="11234"
}
val list = mutableListOf<oomobj>()
try {
while (true){
list.add(oomobj())
}
} catch (e: Throwable) {
println(e.message.toString())
list.clear()
println("list清空")
}
try {
println("list重新进入循环")
while (true){
list.add(oomobj())
}
} catch (e: Throwable) {
println(e.message.toString())
}
}
在catch后将list清空,再次进入循环,看看下图的结果:
从输出的结果上可以看到,进入异常处理后,我们将List清空的,还会继续向下执行,当遇到第二次OOM时又会捕获到输出。
JDK中Error类的的注释(如下)里提到过,Error是一种严重的问题,应用程序不应该捕捉它。所以说捕获OOM只是一个治标的办法,其实最核心的还是要解决内存泄露的问题。
完