Kotlin:安全的 lambda(无内存泄漏)?

2024-01-10

读完后这篇关于内存泄漏的文章 https://medium.com/freenet-engineering/memory-leaks-in-android-identify-treat-and-avoid-d0b1233acc8#.yet4778q1,我想知道在 Kotlin Android 项目中使用 lambda 是否安全。确实,lambda 语法使我的编程更加轻松,但是内存泄漏呢?

作为问题的一个例子,我从我的一个项目中获取了一段代码,我在其中构建了一个 AlertDialog。这段代码位于我的项目的 MainActivity 类中。

fun deleteItemOnConfirmation(id: Long) : Unit {
        val item = explorerAdapter.getItemAt(id.toInt())
        val stringId = if (item.isDirectory) R.string.about_to_delete_folder else R.string.about_to_delete_file

        val dialog = AlertDialog.Builder(this).
                setMessage(String.format(getString(stringId), item.name)).setPositiveButton(
                R.string.ok, {dialog: DialogInterface, id: Int ->
                        val success = if (item.isDirectory) ExplorerFileManager.deleteFolderRecursively(item.name)
                        else ExplorerFileManager.deleteFile(item.name)
                        if (success) {
                            explorerAdapter.deleteItem(item)
                            explorerRecyclerView.invalidate()
                        }
                        else Toast.makeText(this@MainActivity, R.string.file_deletion_error, Toast.LENGTH_SHORT).show()
                    }).setNegativeButton(
                R.string.cancel, {dialog: DialogInterface, id: Int ->
                    dialog.cancel()
        })

        dialog.show()
}

我的问题很简单:为正负按钮设置的两个 lambda 是否会导致内存泄漏? (我的意思是,kotlin lambda 是否只是简单地转换为 Java 匿名函数?)

编辑:也许我已经找到答案了在这个 Jetbrains 主题中 https://discuss.kotlinlang.org/t/function-literals-and-reference-to-enclosing-class/416.


编辑(2017 年 2 月 19 日):我收到了非常全面的reply https://discuss.kotlinlang.org/t/lambdas-and-implicit-references-to-the-instance-of-the-enclosing-class/2288/2?u=storix迈克·赫恩 (Mike Hearn) 关于此问题的评论:

与 Java 一样,Kotlin 中发生的情况在不同情况下会有所不同。

  • 如果 lambda 被传递给内联函数并且没有标记为 noinline,那么整个事情就会消失,并且没有额外的类或 对象被创建。
  • 如果 lambda 没有捕获,那么它将作为单例类发出,其实例被一次又一次地重用(一个类+一个对象 分配)。
  • 如果 lambda 捕获,则每次使用 lambda 时都会创建一个新对象。

因此,除了内联情况外,它的行为与 Java 类似 哪里更便宜。这种高效的 lambda 编码方法 这是 Kotlin 中的函数式编程更具吸引力的原因之一 比在Java中。


编辑(2017 年 2 月 17 日):我已在 中发布了有关此主题的问题Kotlin 讨论 https://discuss.kotlinlang.org/t/lambdas-and-implicit-references-to-the-instance-of-the-enclosing-class/2288。也许 Kotlin 工程师会带来一些新东西。


kotlin lambda 是否只是简单地转换为 Java 匿名函数?

我自己问这个问题(这里一个简单的更正:这些被称为匿名类,而不是函数)。文中并没有明确的答案Koltin文档。他们只是state https://kotlinlang.org/docs/reference/inline-functions.html that

使用高阶函数会带来一定的运行时间损失:每个 函数是一个对象,它捕获一个闭包,即那些变量 在函数体中访问。

他们的意思有点令人困惑在函数体中访问的变量。对封闭类实例的引用也被计算在内吗?

我已经看到您在问题中引用的主题,但目前看来它已经过时了。我找到了更多最新信息here https://discuss.kotlinlang.org/t/lambda-expression-or-anonymous-function-keep-an-implicit-reference-of-the-enclosing-class/1429:

Lambda 表达式或匿名函数保留隐式引用的 封闭类

因此,不幸的是,Kotlin 的 lambda 表达式似乎与 Java 的匿名内部类存在相同的问题。

为什么匿名内部类不好?

来自Java specs https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html:

关联类 O 的直接内部类 C 的实例 i 与 O 的实例,称为直接封闭实例 我。对象的直接封闭实例(如果有)是 对象创建时确定

这意味着匿名类总是有一个implicit对封闭类的实例的引用。由于引用是隐式的,因此无法摆脱它。

看看这个简单的例子

public class YourActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new Thread(new Runnable() {
                 // the inner class will keep the implicit reference to the outer activity
                @Override
                public void run() {
                 // long-running task
                }
        }).start();
   }
}

正如您所看到的,在这种情况下,在执行长时间运行的任务之前,将会出现内存泄漏。解决此问题的一种方法是使用静态嵌套类。

Since Kotlin's 非内联lambda 保留对封闭类实例的引用,它们在内存泄漏方面也有类似的问题。

奖励:与其他 Lambda 实现的快速比较

Java 8 Lambda 表达式

Syntax:

  • 声明SAM(单一抽象方法)接口

    interface Runnable { void run(); }
    
  • 使用此接口作为 lambda 的类型

    public void canTakeLambda(Runnable r) { ... }
    
  • 通过你的 lambda

    canTakeLambda(() -> System.out.println("Do work in lambda..."));
    

内存泄漏问题:如中所述specs http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html:

对此的引用——包括通过 不合格的字段引用或方法调用——是, 本质上,是对最终局部变量的引用。拉姆达机构 包含此类引用捕获此的适当实例。在 其他情况,不保留对此的引用通过对象。

简而言之,如果您不使用封闭类中的任何字段/方法,则不会隐式引用this就像匿名类的情况一样。

逆转录酶

来自docs https://github.com/orfjackal/retrolambda

Lambda 表达式通过将其转换为匿名来向后移植 内部类。这包括使用的优化单例 无状态 lambda 的实例避免重复对象的表达式 分配。

我想,这是不言自明的。

苹果的斯威夫特

Syntax:

  • 声明与 Kotlin 类似,在 Swift 中 lambda 称为闭包:

    func someFunctionThatTakesAClosure(closure: (String) -> Void) {}
    
  • 通过关闭

    someFunctionThatTakesAClosure { print($0) }
    

    Here, $0参考闭包的第一个String争论。这对应于it在科特林中。注意:与 Kotlin 不同,在 Swift 中我们还可以引用其他参数,例如$1, $2 etc.

内存泄漏问题:

在 Swift 中,就像在 Java 8 中一样,闭包捕获了对self (this在 Java 和 Kotlin 中)仅当它访问实例的属性时,例如self.someProperty,或者如果闭包调用实例上的方法,例如self.someMethod().

开发人员还可以轻松指定他们只想捕获弱引用:

   someFunctionThatTakesAClosure { [weak self] in print($0) }

我希望 Kotlin 也能做到这一点:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kotlin:安全的 lambda(无内存泄漏)? 的相关文章

  • Android 构建 gradle 在特定设备上失败

    我面临一个奇怪的问题 当我编译我的应用程序以在 Android 7 0 的设备上运行它时 它可以工作 但是当我尝试为 Android 4 2 1 的设备进行编译时 它会失败并出现以下错误 错误 任务 app transformClasses
  • _bstr_t 内存泄漏

    我有一个 C 代码 但它没有正确释放内存 告诉我哪里错了 这是我的代码 1 void MyClass MyFunction void 2 3 for int i 0 i
  • 在屏幕上随机生成一个圆圈并将其设为绿色或红色

    所以我一直在尝试制作一个游戏应用程序 它可以在 Android 屏幕上随机显示带有文本的红色按钮或带有文本的绿色按钮 如果有人可以帮助我 我将不胜感激 另外 如果有人知道如何做到这一点 我想慢慢地产生更快的酷优势 谢谢 SuppressLi
  • Android,让文本切换器成为中心?

    如何集中我的文本切换器 我尝试过设置重力 但似乎不起作用 ts setFactory new ViewFactory public View makeView TextView t new TextView this t setTypefa
  • Android 上通过 JSCH 的基本 SSH 连接

    作为来自此的用户question https stackoverflow com questions 14323661 simple ssh connect with jsch和这个tutorial http eridem net andr
  • Android 上的硬币识别

    我目前正在开发一个 Android 应用程序 它能够拍摄硬币的现有图像 或者使用内置摄像头扫描单个硬币 非常像 Google Goggles 我正在使用 Android 版 OpenCV 我的问题如下 什么方法最适合使用 OpenCV 在
  • Android,语言文件不起作用

    我现在正在创建一个 Android 应用程序 并尝试为我的母语添加语言文件 但在某种程度上 这对我不起作用 我尝试在两部不同的手机中加载该应用程序 但结果相同 之前创建过语言文件 效果良好 但这次不行 手机设置为瑞典语 语言文件适用于我创建
  • 将寻呼机视为列表视图行项目

    我有一个包含 20 行的列表视图 我想为列表视图中的每一行设置一个视图寻呼机 由于列表视图的行中的项目可能是一个或多个 并且我想使用视图分页器显示列表视图行项目 为此 我使用以下代码 将显示在列表视图行中的自定义布局 作为分页器项目
  • Android Things 文件系统

    我正在 Android 上构建这个应用程序 我希望能够让它访问 U 盘上的媒体文件 甚至树莓派的 SD 卡上的媒体文件 我还不知道我将如何处理这些文件 但我只是想知道它是否可能 如果不是这样也没关系 我还有其他解决方案 但我想我会先从明显的
  • Android 在创建时出现 SQLiteException

    首先我想说我是android新手 所以如果这个问题太愚蠢我很抱歉 我正在为带有两个表的 SQLite 数据库编写一个内容提供程序 表格上是在导航抽屉活动中显示列表 第二个表格是在 ListFragment 中显示 每次启动应用程序时 我都会
  • 我可以使用“导入 com.facebook.FacebookSdk;”使用 Facebook SDK 3.23.1?

    在我的 app build gradle 文件中 我有compile com facebook android facebook android sdk 3 23 1 在我的 BaseActivity java 文件 其中有 public
  • MAT(Eclipse 内存分析器)- 如何从内存转储中查看位图

    I m analyzing memory usage of my Android app with help of Eclipse Memory Analyzer http www eclipse org mat also known as
  • UnsupportedOperationException:特权进程中不允许使用 WebView

    我在用android sharedUserId android uid system 在我的清单中获得一些不可避免的权利 从 HDMI 输入读取安卓盒子 http eweat manufacturer globalsources com s
  • 改造Android基本且简单的问题

    我的服务器返回简单的 Json 结果 如下所示 message Upload Success 我正在尝试将结果放入改造模型类中 public class MyResponse SerializedName message String me
  • EditText 的高度不会扩展到其父级的高度

    我在滚动视图中放置了编辑文本 高度 match parent并期望它的高度等于滚动视图 但事实并非如此 它的高度就像wrap content这意味着如果 EditText 中没有文本 我必须将光标指向要弹出的软键盘的第一 行 我想要的是我可
  • MPAndroidChart:组合图表

    我在用MPAndroidChart 库 https github com PhilJay MPAndroidChart 我想用CombinedChart创建这样的图表 那可能吗 我尝试了一下 但似乎不起作用 因为 这些条目没有按我的预期工作
  • 使用 eclipse 配置mockito 时出现问题。给出错误:java.lang.verifyError

    当我将我的mockito库添加到类路径中 并使用一个简单的mockito示例进行测试时 我尝试使用模拟对象为函数add返回错误的值 我得到java lang verifyerror 以下是用于测试的代码 后面是 logcat Test pu
  • Android 视图和视图组

    在安卓中ViewGroup继承自View A ViewGroup是一个容器 里面装有Views ViewGroup LinearLayout View TextView 为什么 Android 的人们将这种关系定义为Inheritance而
  • 对列表中的一系列整数求和

    假设我有一个这样的列表 List
  • 如何用 XML 制作双渐变(类似 iphone)

    如何使用 XML 制作这种可绘制渐变 我可以做一个从颜色 A 到颜色 B 的简单渐变 但我不知道如何在同一个可绘制对象中组合两个渐变 我终于找到了一个带有图层列表的解决方案 这对我来说已经足够好了

随机推荐

  • 组件中未定义渲染函数或模板:匿名

    我遇到这样的问题 重新加载页面后出现错误 组件中未定义渲染函数或模板 匿名 我认为该错误是由于 socket io 造成的 这个错误不是发生在本地机器上 而是发生在生产上 这是怎么回事 开发者 https dev jujuway com u
  • 如何在Python中编写字符串文字而不必转义它们?

    有没有一种方法可以在Python中声明一个字符串变量 这样它里面的所有内容都会自动转义 或者有它的文字字符值 I m not询问如何用斜杠转义引号 这是显而易见的 我要求的是一种通用的方法 用于将所有内容都放入字符串文字中 这样我就不必手动
  • 在查询中使用 TOP 1 时出现问题

    我编写了以下查询来获取日期 删除它的时间部分并添加我想要的时间 如果我在没有 TOP 子句的情况下运行此查询 则效果很好 但是当我添加它时 它返回以下异常 从字符串转换日期和 或时间时转换失败 这是查询 SELECT TOP 1 CONVE
  • C# List .ConvertAll 效率和开销

    我最近了解了 List 的 ConvertAll 扩展 我今天在工作中在代码中使用了几次它 将我的大量对象列表转换为其他对象的列表 看起来效果真的很好 但是 我不确定与仅迭代列表和转换对象相比 这有多高效或多快 ConvertAll 是否使
  • Android 应用内计费、非消耗品

    我正在实施应用内计费 用户将能够购买优质内容的访问权限 这是典型的非消耗品 假设优质内容是问题应用程序中的额外问题或类别 我用过this http www techotopia com index php Integrating Googl
  • 如何设置UILabel发光效果的颜色?

    我们通常可以设置fontColorUILabel 的实现方式 label textColor self someTextColor 和阴影 发光 label layer shadowColor self someGlowColor labe
  • 如何在shell脚本中调用函数?

    我有一个有条件调用函数的 shell 脚本 例如 if choice true then process install elif choice false then process exit fi process install comm
  • 通过句子或段落训练和评估 spaCy 模型

    观察 段落 I love apple I eat one banana a day句子 I love apple I eat one banana a day这一段有两句话 I love apple and I eat one banana
  • 无法添加实体类型“X”的种子实体,因为没有为所需属性“..ID”提供值

    我在玩机智EF Core 2 1 预览 2 我在使用 HasData Seed 方法时遇到问题OnModelCreating ModelBuilder modelBuilder 我的模型是简单的 POCO 类 没有注释 public cla
  • 无法使用“Regex::replace()”来替换编号的捕获组

    我正在将复数器移植到 Rust 但在使用正则表达式时遇到了一些困难 我无法获取Regex replace 正如我所期望的那样 替换编号捕获组的方法 例如 以下显示空字符串 let re Regex new m l ouse unwrap p
  • 从文件开头删除字节数

    我想复制一个没有前 256 个字节的文件 有没有一个好的方法可以用 python 来做到这一点 我猜想简单的方法是用计数器读取字节 然后仅在达到 256 时才开始复制 我希望有更优雅的方式 Thanks with open input rb
  • 如何在复杂数据的情况下分离行

    说实话这个问题本来就不是我的 这个问题 https stackoverflow com q 67871768 2884859促使我把它放在一个简化的案例中 因此 我必须根据分隔符将输入到单元格 列中 的数据分隔成单独的行 即 在目前的情况下
  • 我从脚本创建了文本区域扩展器,但之后它没有扩展

    不知道标题是否正确 我使用一个脚本创建了一张包含 5 个文本区域且 class expand 的表 当我写入时 该文本区域会扩展 但随后不起作用 写完之后有调用jquery插件的方法吗 在我尝试不创建文本区域之前 我在 html 文件中写入
  • Bash 脚本将文本文件与文件名中的特定子字符串连接起来

    在某个目录中 我有许多包含一堆文本文件的目录 我正在尝试编写一个脚本 仅将每个目录中文件名中包含字符串 R1 的文件连接到该特定目录中的一个文件中 以及将那些文件名中包含 R2 的文件连接到另一个 这是我写的 但它不起作用 bin bash
  • 如何使用设备ID获取USB硬件ID?

    如何使用设备ID获取USB设备的硬件ID 我使用的是vc 6 0 操作系统是xp 使用wmi可以吗 终于解决了我的问题 谢谢你的回复 我在这里发布代码 它可能对某人有用 通过这段代码 我们可以获取与我们系统连接的设备的所有硬件ID HDEV
  • 为什么在 WPF 中的菜单上操作时 TextBox 不会失去焦点?

    如果我编辑与 ViewModel 绑定的 TextBox 上的文本 然后单击主应用程序菜单 以保存数据 ViewModel 不会使用新数据进行更新 因为不知何故 TextBox 不会失去焦点 然后数据未更新 为什么文本框不会失去焦点 我应该
  • Python循环引用

    尝试在同一个文件中拥有两个相互引用的类 让它发挥作用的最佳方法是什么 class Foo object other Bar class Bar object other Foo if name main print all ok 问题似乎在
  • Android 空指针异常 不确定如何修复它

    我的代码中的一行不断收到空指针异常错误 但我不知道如何修复它 它基本上只是另一种方法的副本 所以我不知道为什么它会给我错误 任何帮助 将不胜感激 import java util Calendar import android app Ac
  • Java 上有关无效 XML 字符的错误

    在 Java 上解析 xml 文件时出现错误 An invalid XML character Unicode 0x0 was found in the element content of the document xml 来自 web
  • Kotlin:安全的 lambda(无内存泄漏)?

    读完后这篇关于内存泄漏的文章 https medium com freenet engineering memory leaks in android identify treat and avoid d0b1233acc8 yet4778