[dev_arch_opt_3.0][leakfix]修正由于匿名Runnable对象引用外部类引用造成的内存泄漏

This commit is contained in:
renwj
2023-02-03 17:31:45 +08:00
parent 7992613d72
commit 21d6c665f3
4 changed files with 99 additions and 2 deletions

View File

@@ -0,0 +1,94 @@
package com.mogo.launcher.lancet
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.view.View
import androidx.annotation.*
import androidx.core.view.ViewCompat
import androidx.fragment.app.*
import com.knightboost.lancet.api.*
import com.knightboost.lancet.api.annotations.*
import com.knightboost.lancet.api.annotations.Weaver
import com.mogo.eagle.core.utilcode.kotlin.*
import java.lang.ref.*
import java.lang.reflect.Modifier
import java.util.concurrent.ConcurrentHashMap
@Keep
@Weaver
@Group("memory_leak")
class MemoryLeakFix {
@Insert
@ImplementedInterface("java.lang.Runnable")
@TargetMethod(methodName = "run")
fun runProxy() {
if (AccessSyntheticUtils.isTargetAlive(This.get())) {
Origin.callVoid()
}
}
}
internal class AccessSyntheticUtils {
companion object {
private val fields = ConcurrentHashMap<String, WeakReference<Any>>()
@JvmStatic
fun isTargetAlive(obj: Any): Boolean {
try {
val clazz = obj.javaClass
if (!clazz.isAnonymousClass) {
return true
}
val key = clazz.name
return (fields[key] ?: clazz.declaredFields.find {
it.isSynthetic &&
((it.modifiers and Modifier.STATIC) == 0) &&
(View::class.java.isAssignableFrom(it.type) or
Context::class.java.isAssignableFrom(it.type) or
Fragment::class.java.isAssignableFrom(it.type) or
android.app.Fragment::class.java.isAssignableFrom(it.type) or
Dialog::class.java.isAssignableFrom(it.type)
)
}?.let {
it.isAccessible = true
val wf = WeakReference(it.get(obj), ReferenceQueue())
fields[key] = wf
wf
})?.also {
if (it.isEnqueued) {
//对像被垃圾回收了
fields.remove(key)
}
}?.get()?.let { t ->
when(t) {
is View -> {
ViewCompat.isAttachedToWindow(t)
}
is Activity -> {
!t.isFinishing && !t.isDestroyed
}
is Fragment -> {
!t.isDetached
}
is android.app.Fragment -> {
!t.isDetached
}
is Dialog -> {
t.window?.decorView?.let { v -> ViewCompat.isAttachedToWindow(v) } ?: false
}
else -> {
true
}
}
} ?: true
} catch (t: Throwable) {
t.printStackTrace()
}
return true
}
}
}