弱引用在HarmonyOS上的使用

她是猫鳄鱼
发布于 2024-8-1 16:29
浏览
0收藏

开发者需要依靠弱引用解决垃圾回收相关的内存管理问题。

  • 强引用:默认的引用类型,被强引用的对象不会被垃圾回收。
  • 弱引用:允许对象在没有其他强引用时被垃圾回收,不会阻止垃圾回收器回收该对象。

场景一:使用弱引用打破循环引用,确保对象能够被垃圾回收。

循环引用

只要这个循环引用存在,即使外部没有这两个对象的强引用,它们也不会被垃圾回收。

class Student { 
  teacher: Teacher | null = null; 
} 
class Teacher { 
  student: Student | null = null; 
} 
const sTom = new Student(); 
const sMichael = new Teacher(); 
sTom.teacher = sMichael; 
sMichael.student = sTom;

使用弱引用打破循环引用

由于使用了WeakRef弱引用,只要没有其他强引用指向这个两个对象,它们就可以被垃圾回收,只要有一方使用弱引用,即可解除两者的循环引用。

class Parent { 
  child: WeakRef<Child> | null = null; 
} 
class Child { 
  parent: WeakRef<Parent> | null = null; 
} 
const pMissWang = new Parent(); 
const cMaria = new Child(); 
// 使用 WeakRef 包装对象引用 
pMissWang.child = new WeakRef(cMaria); 
cMaria.parent = new WeakRef(pMissWang);

场景二:WeakMap和WeakSet仅持有对对象的弱引用,和WeakRef一样它们也不会阻止垃圾回收。

WeakSet和WeakMap都是用于存储弱引用的集合类型,WeakSet存储对象,WeakMap存储键值对。

与WeakRef的区别:WeakSet和WeakMap可用来保存引用对象,但不支持取出对象WeakRef支持存取对象。

WeakSet

不能从 WeakSet 中取出或获取某个对象,只能检查是否存在于集合中使用 WeakSet 存储对象并检查是否存在,可以依据这一特性判断对象是否被垃圾回收。

interface Student { 
  name: string; 
} 
const sAlice: Student = { name: 'Alice' }; 
const sBob: Student = { name: 'Bob' }; 
const studentWeakSet = new WeakSet<Student>(); 
// 将学生对象添加到 WeakSet 中 
studentWeakSet.add(sAlice); 
studentWeakSet.add(sBob); 
// 检查学生对象是否存在于 WeakSet 中 
console.log('sAlice exists:', studentWeakSet.has(sAlice)); // 输出: true 
console.log('sBob exists:', studentWeakSet.has(sBob)); // 输出: true 
// 创建一个新的学生对象(不在 WeakSet 中) 
const sEve: Student = { name: 'Eve' }; 
// 检查新学生对象是否存在于 WeakSet 中 
console.log('sEve exists:', studentWeakSet.has(sEve)); // 输出: false 
// 删除一个学生对象 
studentWeakSet.delete(sAlice); 
// 再次检查删除后的学生对象是否存在于 WeakSet 中 
console.log('sAlice exists:', studentWeakSet.has(sAlice)); // 输出: false

WeakMap

不能列出WeakMap中的所有键或值,只能通过已知的键来访问对应的值。使用WeakMap存储键值对并通过已知的键访问值。

interface Teacher { 
  name: string; 
} 
const tSmith: Teacher = { name: 'Mr. Smith' }; 
const tJohnson: Teacher = { name: 'Ms. Johnson' }; 
const teacherCourseMap = new WeakMap<Teacher, string>(); 
// 将教师对象和对应的课程信息添加到 WeakMap 中 
teacherCourseMap.set(tSmith, 'Math'); 
teacherCourseMap.set(tJohnson, 'History'); 
// 通过已知的教师对象获取对应的课程信息 
console.log('tSmith teaches:', teacherCourseMap.get(tSmith)); // 输出: Math 
console.log('tJohnson teaches:', teacherCourseMap.get(tJohnson)); // 输出: History 
// 创建一个新的教师对象作为键(不在 WeakMap 中) 
const tBrown: Teacher = { name: 'Mr. Brown' }; 
// 尝试通过新的教师对象获取课程信息 
console.log('tBrown teaches:', teacherCourseMap.get(tBrown)); // 输出: undefined

WeakRef

用WeakRef创建对象的弱引用,支持在需要时获取原始对象,必须在对象仍然存在时才能获取,如果被回收需要重新创建,一般采用WeakRef的deref()方法获取原始对象。

class FamilyMember { 
} 
// 存储家庭成员的弱引用 
const parentWeakRef = new WeakRef<FamilyMember>(new FamilyMember()); 
// 获取原始家庭成员对象 
const parent = parentWeakRef.deref(); 
// 检查是否存在目标家庭成员对象,如果目标对象已经被回收,deref() 将返回 undefined。 
if (parent) { 
  console.log('Family member exists'); 
} else { 
  console.log('Family member does not exist'); 
}

场景三:弱引用的垃圾回收时机

WeakRef 主要用于允许对象被垃圾回收,但不保证对象何时会被回收,其垃圾回收时机是不确定的。

由于WeakRef不能检测对象何时被垃圾回收,没有提供与垃圾回收事件关联的回调机制,所以只能通过主动轮询的方式定期检查对象是否已经被回收。

interface User { 
  username: string 
} 
const user: User = { username: "john_doe" } 
const userWeakRef = new WeakRef(user) 
//用定时器轮训检测对象是否被回收 
const thetime = setInterval(() => { 
  if (userWeakRef.deref() === undefined) { 
    console.log('Object has been disappear'); 
    clearInterval(thetime);//结束轮询 
  } 
}, 1000);

HarmonyOS可用FinalizationRegistry实现类似监控对象生命周期的能力。

使用FinalizationRegistry注册对象后,当对象被垃圾回收时,会调用提供的回调函数。

// 定义回调函数,当目标对象被垃圾回收时会调用该函数 
function cleanupCallback(heldValue: number) { 
  console.log(`Callback received: ${heldValue}`); 
} 
 
export function demoFinalizationRegistry() { 
  // 创建一个 FinalizationRegistry 实例,传入回调函数 
  const finalizationRegistry = new FinalizationRegistry<number>(cleanupCallback); 
 
  // 定义用于注册和取消注册的类 
  class TargetClass { 
  } 
 
  class UnregisterTokenClass { 
  } 
 
  // 创建对象实例 
  let targetObject: TargetClass = new TargetClass(); 
  let unregisterToken: UnregisterTokenClass = new UnregisterTokenClass(); 
  // 设置传给回调函数的具体数据 
  let dataToCleanup = 1; 
  // 注册对象到 FinalizationRegistry 
  finalizationRegistry.register(targetObject, dataToCleanup, unregisterToken); 
  // 取消注册 
  finalizationRegistry.unregister(unregisterToken); 
}


分类
已于2024-8-1 16:29:11修改
收藏
回复
举报
回复
    相关推荐