不应过早终止的对象的标记接口。
任何具有静态类型包含 Finalizable
的局部变量都保证在执行退出变量作用域的代码块之前保持存活。
一个类型包含 Finalizable
,如果以下条件之一成立:
- 类型是非
Never
子类型Finalizable
,或 - 类型是
T?
或FutureOr<T>
,其中T
包含Finalizable
。
换句话说,当对象通过此类变量引用时,保证它不会被视为不可达,并且变量本身在其作用域内的整个持续时间都被视为存活,即使它在最后一次引用之后。
如果没有在变量的类型上使用此标记接口,变量的值可能在完全执行周围作用域之前被垃圾回收,只要变量肯定不再被引用。这反过来可能会触发 NativeFinalizer
执行回调。当变量的类型包含 Finalizable 时,直到当前使用该变量的代码完成,才会阻止 NativeFinalizer
回调运行。
例如,在执行 someNativeCall
期间,finalizable
保持存活。
void myFunction() {
final finalizable = MyFinalizable(Pointer.fromAddress(0));
someNativeCall(finalizable.nativeResource);
}
void someNativeCall(Pointer nativeResource) {
// ..
}
class MyFinalizable implements Finalizable {
final Pointer nativeResource;
MyFinalizable(this.nativeResource);
}
实现 Finalizable
的类的 this
对象在方法执行期间保持存活。此 this
值被处理为局部变量。
例如,在 myFunction
中执行 someNativeCall
期间,this
保持存活。
class MyFinalizable implements Finalizable {
final Pointer nativeResource;
MyFinalizable(this.nativeResource);
void myFunction() {
someNativeCall(nativeResource);
}
}
void someNativeCall(Pointer nativeResource) {
// ..
}
将涉及可终止类的逻辑实现为实现 Finalizable 的类的函数是一种好的实践。
如果在声明变量的块作用域内部创建闭包,并且该闭包包含对变量的任何引用,则变量在闭包对象保持存活或闭包体执行期间保持存活。
例如,finalizable
由闭包对象保持存活,直到闭包体的末尾。
void doSomething() {
final resourceAction = myFunction();
resourceAction(); // `finalizable` is alive until this call returns.
}
void Function() myFunction() {
final finalizable = MyFinalizable(Pointer.fromAddress(0));
return () {
someNativeCall(finalizable.nativeResource);
};
}
void someNativeCall(Pointer nativeResource) {
// ..
}
class MyFinalizable implements Finalizable {
final Pointer nativeResource;
MyFinalizable(this.nativeResource);
}
只有捕获的变量才由闭包保持存活,而不是所有变量。
例如,finalizable
不由返回的闭包对象保持存活。
void Function() myFunction() {
final finalizable = MyFinalizable(Pointer.fromAddress(0));
final nativeResource = finalizable.nativeResource;
return () {
someNativeCall(nativeResource);
};
}
void someNativeCall(Pointer nativeResource) {
// ..
}
class MyFinalizable implements Finalizable {
final Pointer nativeResource;
MyFinalizable(this.nativeResource);
}
如果从可终止对象中提取的资源逃离了从其提取的可终止变量的作用域,则可能是一个错误。
Finalizable
变量的行为也适用于异步函数。此类变量在声明变量的作用域内或捕获变量的闭包中保持存活,只要在该执行期间可能执行任何代码,即使存在异步延迟。
例如,在执行 await someAsyncCall()
期间,finalizable
保持存活。
Future<void> myFunction() async {
final finalizable = MyFinalizable();
await someAsyncCall();
}
Future<void> someAsyncCall() async {
// ..
}
class MyFinalizable implements Finalizable {
// ..
}
在异步代码中,如果从可终止对象中提取的资源逃离了从其提取的可终止变量的作用域,则可能是一个错误。如果您必须从 Finalizable
提取资源,请确保通过 await
任何使用该资源的异步代码的作用域,使定义 Finalizable 的作用域比资源长。
例如,在 useAsync1
中,this
保持存活,直到 resource
在 useAsync1
中不再使用,但在 useAsync2
和 useAsync3
中则不是。
class MyFinalizable {
final Pointer<Int8> resource;
MyFinalizable(this.resource);
Future<int> useAsync1() async {
return await useResource(resource);
}
Future<int> useAsync2() async {
return useResource(resource);
}
Future<int> useAsync3() {
return useResource(resource);
}
}
/// Does not use [resource] after the returned future completes.
Future<int> useResource(Pointer<Int8> resource) async {
return resource.value;
}
异步函数可能在await
处阻塞,以至于运行时系统可以检测到该await
没有完成的可能性。在这种情况下,位于await
之后的代码将永远不会执行,包括finally
块,变量可能与其他一切一样被视为已死。
如果您自己不打算保持变量存活,请确保将可终结的对象传递给其他函数,而不仅仅是它的资源。
例如,当myFunction
运行到其作用域的末尾时,不会通过finalizable
保持存活,而someAsyncCall
仍然可以继续执行。然而,finalizable
本身是由someAsyncCall
保持存活的。
void myFunction() {
final finalizable = MyFinalizable();
someAsyncCall(finalizable);
}
Future<void> someAsyncCall(MyFinalizable finalizable) async {
// ..
}
class MyFinalizable implements Finalizable {
// ..
}
- 注释
-
- @Since('2.17')
属性
- hashCode → int
- 此对象的哈希码。无设置器继承
- runtimeType → Type
- 对象运行时类型的表示。无设置器继承
方法
-
noSuchMethod(
Invocation invocation) → dynamic - 当访问不存在的方法或属性时被调用。继承
-
toString(
) → String - 此对象的字符串表示。继承
运算符
-
operator ==(
Object other) → bool - 相等运算符。继承