Silentdoer

导航

Dart Finalizer的作用

它和java的finalize方法有点像

/// 文件a
import 'dart:ffi';
import 'package:ffi/ffi.dart';

class FfiData {
    /// Uint64的字节数
    static const _sizeInBytes = 8;
    
    /// 要是final的,因为它和FfiData对象是一对一共生的关系,FfiData对象被GC清理了,其内部的pointer也会被清理(清理逻辑自己写,通过Finalizer实现)
    /// 如果要多个Isolate都用到malloc开辟的空间,这里改成final int address;比较合适;
    final Pointer<Uint64> pointer;
    
    /// 注意,这个是static final的,因为它充当着GC工具的作用,可以为多个FfiData对象清理内部引用的ffi数据,所以必须是static final的
    static final _finalizer = Finalizer<Pointer<Uint64>>((ptr) {
        /// 当当前的FfiData被GC释放时,会触发这里,这个是attach方法里绑定了这样的关系
        print("释放了吗?${ptr.address}");
        malloc.free(ptr);
    });
    
    void test() {
        print("数据指针地址:${pointer.address}");
    }
    
    /// 在构造方法里allocate Pointer指向的空间数据
    FfiData(): pointer = malloc.allocate(sizeOf<Uint64>()) {
        // 注意这段代码,它表示注册当前FfiData对象,和这个FfiData对象释放后要传递给Finalizer初始化时的回调函数的对象
        // 这样放this被GC释放时,DVM会拿到其对应的pointer对象,调用_finalizer初始化时的构造方法里的回调函数;
        // attach是绑定this和pointer,还有个detach可以解绑,可以用于比如提前手动将pointer释放了,这个时候就要解绑了,不然会二次释放
        _finalizer.attach(this, pointer);
    }
}

/// 文件b
String template = "一段很长的内容";
void main() {
    FfiData? data = FfiData();
    data.test();
    // 如果不设置为null会导致下面的循环虽然触发了GC,但是data被认为仍然有用而不会被释放,从而不触发对应的Finalizer对象的回调函数
    data = null;
    int size = 10000;
    List<String> list = [];
    // 用于触发GC
    for (int i = 0; i < size; i++) {
        list.add(template + i.toString());
    }
    print("size:${list.length}");
}

 

posted on 2023-10-13 10:11  Silentdoer  阅读(104)  评论(0编辑  收藏  举报