WeakReference
在文章https://27house.cn/archives/2079中介绍了4种引用类型,其中WeakReference可以与ReferenceQueue来判断对象是否回收。那么其实我们可以使用此方法来监听系统是否进行了GC
WeakReference监听GC
如下所示,通过添加哨兵对象,当触发GC的时候,哨兵对象会被回收,从而获取GC
class SentinelObj
class GcMonitor {
private val TAG = "GcMonitor"
private val queue = ReferenceQueue<Any>()
private var weakReference: WeakReference<Any>? = null
private var thread: Thread? = null
fun startMonitor(call: () -> Unit) {
thread = thread(name = "GcMonitor") {
while (!Thread.currentThread().isInterrupted) {
Log.i(TAG, "开始监听GC")
val result = kotlin.runCatching {
queue.remove()
}
if (result.isSuccess) {
call.invoke()
addSentinelObj()
} else {
Thread.currentThread().interrupt()
}
}
Log.i(TAG, "GcMonitor 退出")
}
addSentinelObj()
}
fun stop() {
thread?.interrupt()
}
private fun addSentinelObj() {
Log.i(TAG, "添加哨兵")
weakReference = WeakReference(SentinelObj(), queue)
}
}
finalize与对象回收
要监听对象是否回收,除了使用WeakReference与ReferenceQueue,还可以使用Java Object对象中的finaliz方法。如下所示
public class SentinelObj extends Object {
@Override
protected void finalize() throws Throwable {
super.finalize();
Log.i("GcMonitor", "finalize!!!");
}
}
番外:如何触发GC
通过系统方法Runtime.getRuntime().gc()与Runtime.getRuntime().runFinalization()只能建议系统进行GC,但是无法保证一定会GC
public void triggerGc() {
long current = System.currentTimeMillis();
if (mDumpHprofMode == ResourceConfig.DumpMode.NO_DUMP
&& current - lastTriggeredTime < getResourcePlugin().getConfig().getScanIntervalMillis() / 2 - 100) {
MatrixLog.v(TAG, "skip triggering gc for frequency");
return;
}
lastTriggeredTime = current;
MatrixLog.v(TAG, "triggering gc...");
Runtime.getRuntime().gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
MatrixLog.printErrStackTrace(TAG, e, "");
}
Runtime.getRuntime().runFinalization();
MatrixLog.v(TAG, "gc was triggered.");
}
使用adb
> adb shell
> adb run-as package-name //获取权限
> ps -A | grep package-name //获取pid
> kill -10 pid //强制触发GC
番外:对象一定会被回收么?
private var weakReference: WeakReference<Any>? = null
private val queue = ReferenceQueue<Any>()
var thread: Thread? = null
fun start() {
thread = thread {
weakReference = WeakReference(SentinelObj(), queue)
//👇🏻让线程存活
while (!Thread.currentThread().isInterrupted) {
try {
Thread.sleep(100)
} catch (e: Exception) {
Thread.currentThread().interrupt()
}
}
}
}
fun stop() {
thread?.interrupt()
}
当我们调用start,将SentinelObj对象使用WeakReference引用,在线程停止前,虽然SentinelObj对象只有一个弱应用,但是GC是不会回收此对象!!!因为在栈中还被引用了。所以我们只需要把代码改到一个单独函数中即可,如前文GcMonitor中的addSentinelObj(),就是为了规避GcMonitor Thread的栈引用SentinelObj,避免GC的回调不会被执行!!!!