我对 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,我能够访问外部作用域中存在的变量,因此它无法被操作系统释放,从而导致内存泄漏,如果是,如何修复它或是否存在背后还有其他原因吗?
但是,现在我在 text_watcher 的 OnTextChanged 函数中使用 textedit 变量:
这是源代码的错觉。正如您所正确指出的,一旦
textedit
函数返回,TextEditOperation
局部变量将被销毁。这并不意味着堆上的
TextEdit
object 一定会被垃圾收集。您的 TextWatcher
匿名对象在实例化时“捕获” textedit
局部变量的 值。换句话说,在
TextWatcher
的实现内部,当您使用 textedit
时,您实际上并没有使用 局部变量,而是引用相同的
TextWatcher
实现的隐式定义的 字段 TextEdit
物体。而且这里不存在内存泄漏。在具有垃圾收集器的语言中,当对象尽管不再需要但仍保持强引用时,就会发生“内存泄漏”。您正在从函数返回 TextEdit
对象,因此可能在其他地方使用它,这意味着程序仍然需要它。另外,函数返回后,对
TextWatcher
对象的唯一强引用是由 TextEdit
对象进行的。并不是 TextWatcher
将 TextEdit
对象保留在内存中,而是相反。一旦 TextEdit
对象符合垃圾回收条件,TextWatcher
对象也符合垃圾回收条件。