HarmonyOS开发,A持有B,B引用A的场景会不会导致内存泄漏,看这里!
问题 :A持有B,B引用A的场景会不会导致内存泄漏?答案 :方舟虚拟机的内存管理和GC采用的是根可达算法,根可达算法可以解决循环引用问题,不会导致A引用B,B引用A的内存泄漏。根可达算法以一系列被称为 “根对象”(如栈中的局部变量、静态变量等)作为起始点,从这些根对象开始向下搜索,能够被搜索到的对象被认为是可达对象,而那些无法被搜索到的对象则被判定为不可达对象,会在垃圾回收时被清理。所以,即使存在
问题 :A持有B,B引用A的场景会不会导致内存泄漏?
答案 :方舟虚拟机的内存管理和GC采用的是根可达算法,根可达算法可以解决循环引用问题,不会导致A引用B,B引用A的内存泄漏。
根可达算法原理
根可达算法以一系列被称为 “根对象”(如栈中的局部变量、静态变量等)作为起始点,从这些根对象开始向下搜索,能够被搜索到的对象被认为是可达对象,而那些无法被搜索到的对象则被判定为不可达对象,会在垃圾回收时被清理。所以,即使存在对象之间的循环引用,只要它们都不可达(即没有根对象能引用到它们),就会被回收。
示例代码:
1. 定义类 A :
class A {
b: B | null = null;
constructor() {
console.log(TEST_TAG, 'A 实例被创建');
}
setB(b: B) {
this.b = b;
}
}
2. 定义类 B :
class B {
a: A | null = null;
constructor() {
console.log(TEST_TAG, 'B 实例被创建');
}
setA(a: A) {
this.a = a;
}
}
3. 主函数调用
@Entry
@Component
struct MyTestPage {
build() {
Button('触发循环引用测试')
.onClick(() => {
let aInstance: A = new A();
let bInstance: B = new B();
aInstance.setB(bInstance);
bInstance.setA(aInstance);
console.log(TEST_TAG, "A 对 B的引用: " + aInstance.b)
console.log(TEST_TAG, "B 对 A的引用: " + bInstance.a)
// console.log(TEST_TAG, "B 对 A的引用: " + JSON.stringify(aInstance.b))
// console.log(TEST_TAG, "B 对 A的引用: " + JSON.stringify(bInstance.a))
});
}
}
代码解释
- 类的定义:A 类有一个私有成员变量 b 用于持有 B 类的实例,B 类有一个私有成员变量 a 用于引用 A 类的实例。
- 循环引用的创建:在MyTestPage 组件的按钮点击事件中,先创建 A 实例并传入一个 B 实例,再将 A 实例赋值给 B 实例的 a 成员变量,从而形成循环引用。
运行结果
点击按钮(也可以快速连续点击),对象之间可以互相调用,不会报错。
至此,以上案例一定程度证明了这种引用方式在HarmonyOS开发中,不会导致内存泄露。
.
.
.
.
.
.
注意事项
上述核心代码中,打印log,调用JSON.stringify(aInstance.b)),应用出现 jscrash 崩溃退出场景。
报错信息为:
Error message:Parameter error. The object circular Reference,jscrash,表明在处理对象时出现了循环引用的问题。循环引用指的是对象之间相互引用,形成了一个闭环,这在某些操作(比如序列化对象,像使用 JSON.stringify 时)中会引发错误,因为序列化工具无法处理这种无限循环的引用结构。
提醒:在序列化时,工具会不断地顺着引用去解析对象,而循环引用会造成无限循环,最终导致报错。
更多推荐



所有评论(0)