OOM
申请内存超过堆内存剩余空间的最大值
内存抖动
原因
短时间大量的对象创建销毁,导致频繁的GC
后果
1.导致卡顿
Gc过程会将所有的进程挂起,主线程如果被频繁的挂起就会导致卡顿
ka.png
2.OOM
例如标记清除算法,会导致内存碎片,当需要一个较大的内连续存空间(为对象分配内存时会选择连续的内存),会出现OOM问题
flagclear.png
实例
自定义view
class ProgressView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private var progress = 0f
get() = field
set(value) {
field = value
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val paint = Paint()
paint.strokeWidth =3.0f
paint.isAntiAlias = true
paint.isDither = true
val path = Path()
val path1 = Path()
val path2 = Path()
val path3 = Path()
}
fun startAnimation(){
val objectAnimator = ObjectAnimator.ofFloat(this,"progress",1f,100f)
objectAnimator.duration = 400
objectAnimator.repeatCount = -1
objectAnimator.start()
}
}
查看内存使用
抖动原因
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val paint = Paint()
paint.strokeWidth =3.0f
paint.isAntiAlias = true
paint.isDither = true
val path = Path()
val path1 = Path()
val path2 = Path()
val path3 = Path()
}
ondraw()中频繁的创建paint、path对象,导致内存中不停的创建销毁。所以要将对象的创建放在外面
lateinit var paint:Paint
lateinit var path:Path
init {
paint = Paint()
path = Path()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
paint.strokeWidth =3.0f
paint.isAntiAlias = true
paint.isDither = true
path.lineTo(0f,0f)
path.reset()
path.moveTo(100f,100f)
}
after.png
内存泄漏
程序中动态分配的堆内存由于某种原因程序未释放,或者无法释放,造成内存的浪费。
长生命周期强引用短生命周期对象,导致段短生命周期对象无法被回收!
判断对象是否可回收
> 可达性算法
> 当一个对象到Gcroot对象的引用链不可达时,对象就可以被回收。否则不可回收
> GCroot对象如静态变量
内存泄漏常见案例
单例导致的内存泄漏
作为GCroot,持有短生命周期如activity引用,导致activity不能被回收
public class Manager {
//GcRoot
private static Manager mManager = new Manager();
private Context mContext;
public static Manager getInstance() {
return mManager;
}
public void init(Context context) {
mContext = context;
}
}
泄漏原因
由于mManager持有context,mManager时静态的和app的生命周期一样长,所以导致Activity不能被释放
解决方法
传递application
val instance = Manager.getInstance()
instance.init(application)
handler导致的内存泄漏(匿名内部类,非静态内部类)
var i = 0
fun text(){
val handler = Handler(Looper.getMainLooper()!!)
handler.postDelayed(object: Runnable{
override fun run() {
println("i==$i")
}
},100000)
}
泄漏原因
Runnable是匿名内部类,会持有外部类的引用,runnable又会被封装到message,message会被放到消息队列中,如果消息没有被处理,引用不会被释放,导致activity不能被释放
解决方法
override fun onDestroy() {
super.onDestroy()
//activity 销毁时 清除消息
handler.removeCallbacksAndMessages(null)
}
或
inner class MRunnable:Runnable{
constructor(context: Context){
//弱引用 当Gc时会被回收
val weakReference = WeakReference(context)
}
override fun run() {
println("i==$i")
}
}
资源使用未关闭
try {
val stream = FileOutputStream("")
stream.write("".toByteArray())
stream.close()
}catch (e:Exception){
e.printStackTrace()
}
解决方法
try {
fos = FileOutputStream("")
fos?.write("".toByteArray())
fos?.close()
}catch (e:Exception){
e.printStackTrace()
}finally {
//需要防止异常情况 未关闭
if(fos != null){
fos?.close()
}
}
集合类
当使用集合时只有添加元素,没有删除元素。如Eventbus只有注册没有注销
工具分析
dump内存
dump.png分析内存中对象
leak.png
网友评论