You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Kotlin Lambda会被垃圾回收而普通对象不会?

Kotlin Lambda作为监听器被弱引用持有后被GC的原因及行为解析

1. 现象的核心原因

问题出在Kotlin对SAM转换的处理逻辑,以及两种监听器实例的引用持有关系差异:

  • 匿名对象(anObject):它是直接实现Notifications.Listener的实例,被companion object的val anObject强引用持有。由于companion object是单例,生命周期和应用一致,这个对象始终有强引用兜底,因此弱引用永远不会被GC回收,get()方法始终返回非null。

  • Lambda(aLambda):它本身是一个函数类型对象((Bundle?, Fragment?) -> Unit),而非Listener接口实例。当调用addListener(aLambda)时,Kotlin会自动执行SAM转换:临时生成一个Listener接口的实现类实例,这个实例的onNotification方法会委托调用aLambda函数。但关键是:这个SAM转换生成的Listener实例,并没有被任何强引用持有——companion object只持有aLambda函数对象的强引用,不持有转换后的Listener实例。因此这个Listener实例只有Notifications中的弱引用指向它,GC触发时就会被回收,导致弱引用get()返回null。

简单来说:你持有了Lambda的引用,但这和转换后的Listener实例是两个不同的对象,后者没有强引用兜底,自然会被GC回收。

2. 这是Kotlin的预期行为吗?

是的,这是Kotlin SAM转换机制的预期设计:
SAM转换是按需临时生成实例,编译器不会自动将转换后的接口实例存储到强引用变量中,除非你显式地将其赋值并持有。比如修改代码,把SAM转换后的实例存起来:

val samListener: Notifications.Listener = aLambda
Notifications.addListener(samListener)

此时samListener被companion object强引用,对应的Listener实例就不会被GC回收,和匿名对象的表现完全一致。


原始代码参考

Kotlin代码

companion object {

    // This lambda IS being garbage collected after a while 
    val aLambda: (bundle: Bundle?, caller: Fragment?) -> Unit = { _, _ -> if (something()) processRequest() }

    // This object IS NOT being garbage collected
    val anObject = object: Notifications.Listener {
        override fun onNotification(bundle: Bundle?, caller: Fragment?) {
            if (something()) processRequest()
        }
    }

    init {
        // This Notifications class holds weak references to both the lambda & object the same way
        Notifications.addListener(aLambda)
        Notifications.addListener(anObject)
    }
}

Java代码

public class Notifications {
    
    private static ArrayList<WeakReference<Listener>> listenersArray = new ArrayList<>();

    public static void addListener(@NonNull Listener listener) {
        listenersArray.add(new WeakReference<>(listener));
    }

    public static void notify(@Nullable Bundle bundle, @Nullable Fragment caller) {
        for (WeakReference<Listener> weakListener : listenersArray) {
            Listener listener = weakListener.get();
            if (listener != null) {
                listener.onNotification(bundle, caller);
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Doron Yakovlev Golani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 00:33:13