Kotlin 中由于闭包导致内存泄漏?

问题描述 投票:0回答:1

我对 Kotlin 中的内存管理有基本的了解,即局部变量存储在堆栈中并由操作系统管理,对象在堆上创建并由 JVM 管理它们。此外,对象作为引用的副本传递,原始类型作为函数中的副本传递。

在下面的代码中,我创建了一个 TextEditOperation 函数,该函数以编程方式创建 EditText 并使用指令对象设置其属性,并向其添加 TextWatcher,最后将 edittext 视图添加到父相对布局。

public fun TextEditOperation (pInstructionSetIndex: Int, pInstructionIndex: Int): View? 
{
    val instruction: InstructionKernelAndroid
    val context: Context?
    val activity: Activity
    val textedit: EditText
    val parent_view: RelativeLayout

    // fetch the instruction
    instruction = InstructionSetMgr.uAndroidOSInstructionSetList[pInstructionSetIndex][pInstructionIndex]

    // get activity's Context
    context = ProcessStates.GetMainActivityContext ()

    // cast activity's context to activity to use it's method
    activity = context as Activity

    // get parent view
    parent_view = activity.findViewById (instruction.GetParentID ()) as RelativeLayout

    // create view
    textedit = EditText (context)

    // set view properties

    textedit.id = instruction.GetElementID ()
    textedit.hint = instruction.GetHintText ()
    textedit.layoutParams = RelativeLayout.LayoutParams (
        instruction.GetWidth (),
        instruction.GetHeight ()
    )
    textedit.x = instruction.GetX ()
    textedit.y = instruction.GetY ()
    textedit.setBackgroundColor (Color.parseColor (instruction.GetBackgroundColor ()))
    textedit.setTextColor (Color.parseColor (instruction.GetTextColor ()))
    
    // create and add a TextWatcher to the EditText

        val text_watcher: TextWatcher

    text_watcher = object : TextWatcher {
    
        override fun beforeTextChanged (s: CharSequence, start: Int, count: Int, after: Int)
        {
            
        }
    
        override fun onTextChanged (s: CharSequence, start: Int, before: Int, count: Int) 
        {
            TextChanged (pInstructionSetIndex + 1, textedit.length (), textedit.id)
        }
    
        override fun afterTextChanged (s: Editable)
        {
            
        }
    } 
    // add the textwatcher
    textedit.addTextChangedListener (text_watcher)
    
    // add view to parent view
    parent_view.addView (textedit);

    return textedit;  
}

现在,我的理解是,如果 text_watcher 对象不存在,那么对于 line

textedit = EditText(上下文)

EditText(context) 对象将在堆上创建(由 JVM 管理),引用该对象的变量 textedit(由操作系统管理)将在堆栈上创建。因此,一旦函数作用域结束,操作系统就会从堆栈内存中清除 textedit 变量。

但是,现在我在 text_watcher 的 OnTextChanged 函数中使用 textedit 变量:

override fun onTextChanged (s: CharSequence, start: Int, before: Int, count: Int) 
{
     TextChanged (pInstructionSetIndex + 1, textedit.length (), textedit.id)
}

在 TextEditOperation 的函数范围结束后,onTextChanged 函数仍将被调用。我如何能够使用现在应该已被操作系统删除的 textedit 变量访问 EditText 的长度和 id?

是否是因为 kotlin 中的closures,我能够访问外部作用域中存在的变量,因此它无法被操作系统释放,从而导致内存泄漏,如果是,如何修复它或是否存在背后还有其他原因吗?

android kotlin memory-management memory-leaks textwatcher
1个回答
0
投票

但是,现在我在 text_watcher 的 OnTextChanged 函数中使用 textedit 变量:

这是源代码的错觉。正如您所正确指出的,一旦

textedit
函数返回,TextEditOperation
局部变量
将被销毁。这并不意味着堆上的
TextEdit
object 一定会被垃圾收集。您的
TextWatcher
匿名对象在实例化时“捕获” textedit
局部变量
。换句话说,在 TextWatcher 的实现内部,当您使用
textedit
时,您实际上并没有使用
局部变量
,而是引用相同的 TextWatcher 实现的隐式定义的 字段
TextEdit
物体。
而且这里不存在内存泄漏。在具有垃圾收集器的语言中,当对象尽管不再需要但仍保持强引用时,就会发生“内存泄漏”。您正在从函数返回 

TextEdit

对象,因此可能在其他地方使用它,这意味着程序仍然需要它。另外,函数返回后,对

TextWatcher
对象的唯一强引用是由
TextEdit
对象进行的。并不是
TextWatcher
TextEdit
对象保留在内存中,而是相反。一旦
TextEdit
对象符合垃圾回收条件,
TextWatcher
对象也符合垃圾回收条件。
    

© www.soinside.com 2019 - 2024. All rights reserved.