HarmonyOS APP开发:对象池模式与对象复用优化
HarmonyOS APP开发:对象池模式与对象复用优化
📌 核心要点:掌握对象池设计原理与通用实现,通过消息池、事件池、组件池三大实战场景,彻底解决频繁对象创建导致的内存抖动与GC压力问题。
一、背景与动机
想象一下这个场景:你的鸿蒙应用每秒要处理上百条消息,每条消息都需要创建一个消息对象,处理完就丢弃。这意味着每秒有上百个对象被创建又被回收,年轻代的Eden区像坐过山车一样忽上忽下,GC被频繁触发,UI线程时不时卡一下——用户看到的,就是列表滚动时偶尔的"卡壳"。
你可能会想:能不能不每次都新建对象,而是"回收"用过的对象,下次直接复用?这就是对象池(Object Pool)模式的核心思想——用时间换空间,用复用换分配。
对象池模式并不是什么新鲜概念,它在游戏开发、高频交易、网络通信等领域早已是标配。但在鸿蒙应用开发中,很多开发者还没有意识到它的价值。原因很简单——鸿蒙应用的开发历史还比较短,大部分应用还处于"功能实现"阶段,还没到"性能优化"的阶段。但随着鸿蒙生态的成熟和用户对体验要求的提高,对象池优化将成为鸿蒙开发者的必备技能。
本文将从对象池的设计原理出发,实现一个通用对象池,然后通过消息池、事件池、组件池三大实战场景,展示对象池在鸿蒙应用中的实际应用。最后,我们还会讨论对象池与GC的关系,以及对象池的适用边界——毕竟,不是所有场景都适合使用对象池。
二、核心原理
2.1 对象池设计原理
对象池的核心思想非常简单:预先创建一批对象放入池中,需要时从池中取出,用完归还到池中。就像图书馆的借书系统——书不需要每次都印新的,借出去的书还回来后,下一个人可以继续借。
flowchart TD
A[需要对象] --> B{对象池是否为空?}
B -->|否| C[从池中取出对象]
B -->|是| D{是否达到最大容量?}
D -->|否| E[创建新对象]
D -->|是| F[等待或返回null]
C --> G[使用对象]
E --> G
G --> H[使用完毕]
H --> I{池是否已满?}
I -->|否| J[重置对象状态]
J --> K[归还到池中]
I -->|是| L[丢弃对象 让GC回收]
K --> B
classDef poolStyle fill:#6C5CE7,stroke:#5B4CC4,color:#fff,stroke-width:2px
classDef actionStyle fill:#00B894,stroke:#00A381,color:#fff,stroke-width:2px
classDef decisionStyle fill:#FDCB6E,stroke:#F39C12,color:#333,stroke-width:2px
classDef discardStyle fill:#E17055,stroke:#D63031,color:#fff,stroke-width:2px
class A,B,D,I decisionStyle
class C,E,G,H,J,K actionStyle
class F,L discardStyle
2.2 对象池容量管理策略
对象池的容量管理是设计的核心。容量太小,起不到复用效果;容量太大,又浪费内存。常见的容量管理策略如下:
| 策略 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 固定容量 | 预先设定固定大小 | 实现简单,内存可控 | 无法应对突发流量 |
| 动态扩容 | 根据需求自动扩容 | 灵活适应不同负载 | 扩容时有分配开销 |
| 弹性收缩 | 空闲时自动缩减 | 节省内存 | 缩减后可能再次扩容 |
| 分代管理 | 按对象年龄分区管理 | 避免长期持有不活跃对象 | 实现复杂 |
2.3 对象池与GC的关系
对象池和GC看似矛盾——对象池阻止了对象被GC回收,而GC的目标就是回收不再使用的对象。但实际上,它们是互补的关系:
flowchart LR
subgraph 无对象池["❌ 无对象池"]
direction TB
A1[创建对象] --> A2[使用对象]
A2 --> A3[丢弃对象]
A3 --> A4[GC回收]
A4 --> A5[再次创建]
A5 --> A2
end
subgraph 有对象池["✅ 有对象池"]
direction TB
B1[从池中取出] --> B2[使用对象]
B2 --> B3[重置状态]
B3 --> B4[归还到池]
B4 --> B1
end
无对象池 -.->|频繁GC| 有对象池
classDef noPoolStyle fill:#E74C3C,stroke:#C0392B,color:#fff,stroke-width:2px
classDef poolStyle fill:#2ECC71,stroke:#27AE60,color:#fff,stroke-width:2px
class A1,A2,A3,A4,A5 noPoolStyle
class B1,B2,B3,B4 poolStyle
关键洞察:对象池通过复用对象减少了GC的触发频率,但池中的对象本身不会被GC回收。因此,对象池的容量必须合理控制,否则池本身可能成为内存问题。
2.4 对象池适用场景
对象池并非万能药,它适用于以下场景:
- ✅ 对象创建成本高:如数据库连接、网络Socket
- ✅ 对象使用频率高:如消息处理、事件分发
- ✅ 对象生命周期短:用完即弃的临时对象
- ✅ 对象状态可重置:可以被"清洗"后复用
不适用于以下场景:
- ❌ 对象创建成本极低:如简单数据对象,创建开销可忽略
- ❌ 对象使用频率低:偶尔才用一次,复用价值不大
- ❌ 对象状态不可重置:如包含不可变数据的对象
- ❌ 对象需要线程安全:多线程环境下池的同步开销可能抵消复用收益
三、代码实战
3.1 基础示例:通用对象池实现
下面实现一个类型安全、支持容量管理和状态重置的通用对象池:
// 可重置接口 - 对象必须实现此接口才能被对象池管理
interface Poolable {
// 重置对象状态,使其可以被复用
reset(): void
}
// 对象池配置
interface ObjectPoolConfig<T extends Poolable> {
name: string // 对象池名称
factory: () => T // 对象工厂函数
initialSize: number // 初始容量
maxSize: number // 最大容量
resetOnReturn: boolean // 归还时是否自动重置
shrinkIntervalMs: number // 弹性收缩检查间隔(0=不收缩)
shrinkThreshold: number // 收缩阈值(空闲对象占比超过此值时收缩)
}
// 通用对象池
class ObjectPool<T extends Poolable> {
private pool: T[] = [] // 可用对象列表
private activeCount: number = 0 // 正在使用的对象数
private config: ObjectPoolConfig<T> // 配置
private shrinkTimerId: number = -1 // 收缩定时器
private stats: PoolStats = { // 统计信息
totalCreated: 0,
totalBorrowed: 0,
totalReturned: 0,
totalDropped: 0,
hitRate: 0
}
constructor(config: ObjectPoolConfig<T>) {
this.config = config
// 预创建初始对象
for (let i = 0; i < config.initialSize; i++) {
this.pool.push(config.factory())
this.stats.totalCreated++
}
// 启动弹性收缩
if (config.shrinkIntervalMs > 0) {
this.shrinkTimerId = setInterval(() => {
this.tryShrink()
}, config.shrinkIntervalMs) as number
}
}
// 从池中借出对象
borrow(): T {
let obj: T
if (this.pool.length > 0) {
// 池中有可用对象
obj = this.pool.pop()!
} else if (this.stats.totalCreated < this.config.maxSize) {
// 池为空但未达上限,创建新对象
obj = this.config.factory()
this.stats.totalCreated++
} else {
// 已达上限,创建临时对象(不纳入池管理)
console.warn(`[ObjectPool:${this.config.name}] 已达最大容量,创建临时对象`)
obj = this.config.factory()
this.stats.totalDropped++
}
this.activeCount++
this.stats.totalBorrowed++
this.updateHitRate()
return obj
}
// 归还对象到池中
return(obj: T): void {
this.activeCount--
this.stats.totalReturned++
// 自动重置对象状态
if (this.config.resetOnReturn) {
obj.reset()
}
// 池未满则归还,否则丢弃
if (this.pool.length < this.config.maxSize) {
this.pool.push(obj)
} else {
// 超出容量,让GC回收
this.stats.totalDropped++
}
}
// 获取当前池状态
getStatus(): PoolStatus {
return {
available: this.pool.length,
active: this.activeCount,
totalCreated: this.stats.totalCreated,
hitRate: this.stats.hitRate
}
}
// 获取统计信息
getStats(): PoolStats {
return { ...this.stats }
}
// 清空对象池
clear(): void {
this.pool = []
this.activeCount = 0
}
// 销毁对象池
destroy(): void {
this.clear()
if (this.shrinkTimerId !== -1) {
clearInterval(this.shrinkTimerId)
this.shrinkTimerId = -1
}
}
// 尝试弹性收缩
private tryShrink(): void {
const totalCapacity = this.pool.length + this.activeCount
if (totalCapacity === 0) return
const idleRatio = this.pool.length / totalCapacity
if (idleRatio > this.config.shrinkThreshold) {
// 空闲对象过多,收缩到初始大小
const targetSize = Math.max(this.config.initialSize, this.activeCount)
while (this.pool.length > targetSize) {
this.pool.pop()
}
console.info(`[ObjectPool:${this.config.name}] 弹性收缩至 ${this.pool.length} 个对象`)
}
}
// 更新命中率
private updateHitRate(): void {
if (this.stats.totalBorrowed > 0) {
const hits = this.stats.totalBorrowed - this.stats.totalDropped
this.stats.hitRate = hits / this.stats.totalBorrowed
}
}
}
interface PoolStats {
totalCreated: number
totalBorrowed: number
totalReturned: number
totalDropped: number
hitRate: number
}
interface PoolStatus {
available: number
active: number
totalCreated: number
hitRate: number
}
3.2 进阶示例:消息池与事件池
下面展示对象池在消息处理和事件分发中的实际应用:
// ===== 消息对象池 =====
// 消息对象 - 实现Poolable接口
class Message implements Poolable {
type: string = '' // 消息类型
payload: string = '' // 消息内容
timestamp: number = 0 // 时间戳
source: string = '' // 消息来源
priority: number = 0 // 优先级
// 重置消息状态
reset(): void {
this.type = ''
this.payload = ''
this.timestamp = 0
this.source = ''
this.priority = 0
}
// 设置消息内容(链式调用)
with(type: string, payload: string, source: string = '', priority: number = 0): Message {
this.type = type
this.payload = payload
this.timestamp = Date.now()
this.source = source
this.priority = priority
return this
}
}
// 消息池 - 管理消息对象的复用
class MessagePool {
private pool: ObjectPool<Message>
constructor() {
this.pool = new ObjectPool<Message>({
name: 'MessagePool',
factory: () => new Message(),
initialSize: 20,
maxSize: 100,
resetOnReturn: true,
shrinkIntervalMs: 30000, // 30秒检查一次
shrinkThreshold: 0.7 // 空闲超过70%时收缩
})
}
// 获取一条消息
acquire(type: string, payload: string, source: string = '', priority: number = 0): Message {
return this.pool.borrow().with(type, payload, source, priority)
}
// 释放消息
release(msg: Message): void {
this.pool.return(msg)
}
// 获取池状态
getStatus(): PoolStatus {
return this.pool.getStatus()
}
}
// ===== 事件对象池 =====
// 事件对象
class AppEvent implements Poolable {
eventName: string = '' // 事件名称
data: Map<string, Object> = new Map() // 事件数据
timestamp: number = 0 // 时间戳
propagationStopped: boolean = false // 是否停止传播
reset(): void {
this.eventName = ''
this.data.clear() // 清空数据Map
this.timestamp = 0
this.propagationStopped = false
}
// 设置事件数据
setData(key: string, value: Object): AppEvent {
this.data.set(key, value)
return this
}
// 停止事件传播
stopPropagation(): void {
this.propagationStopped = true
}
}
// 事件池
class EventPool {
private pool: ObjectPool<AppEvent>
constructor() {
this.pool = new ObjectPool<AppEvent>({
name: 'EventPool',
factory: () => new AppEvent(),
initialSize: 10,
maxSize: 50,
resetOnReturn: true,
shrinkIntervalMs: 60000,
shrinkThreshold: 0.6
})
}
// 获取事件对象
acquire(eventName: string): AppEvent {
const event = this.pool.borrow()
event.eventName = eventName
event.timestamp = Date.now()
return event
}
// 释放事件
release(event: AppEvent): void {
this.pool.return(event)
}
}
// ===== 在事件总线中使用对象池 =====
class PooledEventBus {
private listeners: Map<string, Array<(event: AppEvent) => void>> = new Map()
private eventPool: EventPool = new EventPool()
// 注册事件监听
on(eventName: string, listener: (event: AppEvent) => void): void {
const list = this.listeners.get(eventName) || []
list.push(listener)
this.listeners.set(eventName, list)
}
// 注销事件监听
off(eventName: string, listener: (event: AppEvent) => void): void {
const list = this.listeners.get(eventName)
if (list) {
const index = list.indexOf(listener)
if (index !== -1) {
list.splice(index, 1)
}
}
}
// 发送事件 - 使用对象池
emit(eventName: string, data?: Record<string, Object>): void {
const event = this.eventPool.acquire(eventName)
// 设置事件数据
if (data) {
for (const key of Object.keys(data)) {
event.setData(key, data[key])
}
}
// 分发事件
const list = this.listeners.get(eventName)
if (list) {
for (const listener of list) {
if (event.propagationStopped) break
try {
listener(event)
} catch (e) {
console.error(`[EventBus] 事件处理异常: ${eventName}`, e)
}
}
}
// ✅ 释放事件对象回池中
this.eventPool.release(event)
}
}
// 全局事件总线
const pooledEventBus = new PooledEventBus()
3.3 完整示例:组件池与列表项复用
在长列表场景中,列表项的频繁创建和销毁是内存抖动的主要来源。下面实现一个组件池,用于复用列表项的数据模型:
// ===== 列表项数据模型 - 支持对象池复用 =====
class ListItemData implements Poolable {
id: string = ''
title: string = ''
subtitle: string = ''
icon: string = ''
extra: string = ''
isSelected: boolean = false
timestamp: number = 0
reset(): void {
this.id = ''
this.title = ''
this.subtitle = ''
this.icon = ''
this.extra = ''
this.isSelected = false
this.timestamp = 0
}
// 批量设置属性
configure(config: {
id: string
title: string
subtitle?: string
icon?: string
extra?: string
}): ListItemData {
this.id = config.id
this.title = config.title
this.subtitle = config.subtitle || ''
this.icon = config.icon || ''
this.extra = config.extra || ''
this.timestamp = Date.now()
return this
}
}
// 列表项数据池
class ListItemPool {
private pool: ObjectPool<ListItemData>
constructor() {
this.pool = new ObjectPool<ListItemData>({
name: 'ListItemPool',
factory: () => new ListItemData(),
initialSize: 30,
maxSize: 200,
resetOnReturn: true,
shrinkIntervalMs: 60000,
shrinkThreshold: 0.5
})
}
// 获取列表项
acquire(config: { id: string; title: string; subtitle?: string; icon?: string; extra?: string }): ListItemData {
return this.pool.borrow().configure(config)
}
// 释放列表项
release(item: ListItemData): void {
this.pool.return(item)
}
// 批量获取
acquireBatch(configs: Array<{ id: string; title: string; subtitle?: string; icon?: string; extra?: string }>): ListItemData[] {
return configs.map(config => this.acquire(config))
}
// 批量释放
releaseBatch(items: ListItemData[]): void {
items.forEach(item => this.release(item))
}
getStatus(): PoolStatus {
return this.pool.getStatus()
}
}
// ===== 使用对象池的高性能列表组件 =====
@Entry
@Component
struct PooledListPage {
@State displayItems: ListItemData[] = []
private itemPool: ListItemPool = new ListItemPool()
private currentBatch: ListItemData[] = [] // 当前批次,用于释放
build() {
Column({ space: 12 }) {
// 池状态展示
Row({ space: 16 }) {
Text(`池状态: 可用${this.itemPool.getStatus().available} | 活跃${this.itemPool.getStatus().active}`)
.fontSize(12)
.fontColor('#666666')
}
.padding(8)
.width('100%')
.backgroundColor('#F0F0F0')
.borderRadius(8)
// 列表
List({ space: 4 }) {
ForEach(this.displayItems, (item: ListItemData) => {
ListItem() {
this.ListItemView(item)
}
}, (item: ListItemData) => item.id)
}
.width('100%')
.layoutWeight(1)
// 操作按钮
Row({ space: 12 }) {
Button('加载首页').onClick(() => this.loadPage('home'))
Button('加载推荐').onClick(() => this.loadPage('recommend'))
Button('加载收藏').onClick(() => this.loadPage('favorite'))
}
}
.padding(16)
.onDisappear(() => {
// 页面销毁时释放当前批次
this.releaseCurrentBatch()
})
}
// 列表项视图
@Builder
ListItemView(item: ListItemData) {
Row({ space: 12 }) {
// 图标
Text(item.icon || '📋')
.fontSize(24)
// 文字内容
Column({ space: 4 }) {
Text(item.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.maxLines(1)
if (item.subtitle) {
Text(item.subtitle)
.fontSize(12)
.fontColor('#999999')
.maxLines(1)
}
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
// 额外信息
if (item.extra) {
Text(item.extra)
.fontSize(12)
.fontColor('#FF6B6B')
}
}
.padding(12)
.borderRadius(8)
.backgroundColor('#FFFFFF')
}
// 加载页面数据 - 使用对象池
private loadPage(pageType: string): void {
// 释放当前批次
this.releaseCurrentBatch()
// 模拟获取新数据
const rawData = this.fetchPageData(pageType)
// ✅ 从对象池获取列表项
this.currentBatch = this.itemPool.acquireBatch(rawData)
this.displayItems = [...this.currentBatch]
}
// 释放当前批次
private releaseCurrentBatch(): void {
if (this.currentBatch.length > 0) {
this.itemPool.releaseBatch(this.currentBatch)
this.currentBatch = []
this.displayItems = []
}
}
// 模拟数据获取
private fetchPageData(pageType: string): Array<{ id: string; title: string; subtitle: string; icon: string; extra: string }> {
const titles: Record<string, string[]> = {
home: ['今日热点', '科技前沿', '生活百态', '财经观察', '体育快讯'],
recommend: ['为你推荐', '热门话题', '精选内容', '达人分享', '新品上线'],
favorite: ['我的收藏', '稍后阅读', '历史浏览', '点赞文章', '评论互动']
}
const pageTitles = titles[pageType] || titles.home
return pageTitles.map((title, index) => ({
id: `${pageType}_${index}`,
title,
subtitle: `${pageType}频道的精彩内容`,
icon: ['🔥', '💡', '🌍', '💰', '⚽'][index % 5],
extra: index === 0 ? 'NEW' : ''
}))
}
}
// ===== 对象池性能对比测试 =====
class PoolPerformanceTest {
// 不使用对象池
static testWithoutPool(iterations: number): number {
const startTime = Date.now()
for (let i = 0; i < iterations; i++) {
const msg = new Message()
msg.with('test', `payload_${i}`, 'benchmark')
// 模拟使用
const _ = msg.type
// 对象被丢弃,等待GC回收
}
return Date.now() - startTime
}
// 使用对象池
static testWithPool(iterations: number): number {
const pool = new MessagePool()
const startTime = Date.now()
for (let i = 0; i < iterations; i++) {
const msg = pool.acquire('test', `payload_${i}`, 'benchmark')
// 模拟使用
const _ = msg.type
// ✅ 归还到池中
pool.release(msg)
}
return Date.now() - startTime
}
// 运行对比测试
static runBenchmark(): void {
const iterations = 10000
console.info('=== 对象池性能对比测试 ===')
console.info(`测试次数: ${iterations}`)
const timeWithoutPool = this.testWithoutPool(iterations)
console.info(`无对象池: ${timeWithoutPool}ms`)
const timeWithPool = this.testWithPool(iterations)
console.info(`有对象池: ${timeWithPool}ms`)
const improvement = ((timeWithoutPool - timeWithPool) / timeWithoutPool * 100).toFixed(1)
console.info(`性能提升: ${improvement}%`)
}
}
四、踩坑与注意事项
坑点1:忘记归还对象——比内存泄漏更可怕
使用对象池时,如果借出对象后忘记归还,池中的可用对象会越来越少,最终退化为每次都创建新对象,对象池形同虚设。更糟糕的是,由于池持有对象的引用,这些对象永远不会被GC回收,造成真正的内存泄漏。
正确做法:使用try-finally确保对象一定被归还,或者使用回调模式自动管理生命周期。
// ✅ 安全的对象池使用模式
function processMessage(pool: MessagePool, type: string, payload: string): void {
const msg = pool.acquire(type, payload)
try {
// 处理消息
handleMessage(msg)
} finally {
// 确保归还
pool.release(msg)
}
}
坑点2:重置不彻底导致脏数据
对象归还到池中后,如果reset()方法没有彻底清除所有状态,下一个使用者可能会读到上一个用户遗留的"脏数据"。这在多线程环境下尤其危险。
正确做法:reset()方法必须清除所有业务字段,包括嵌套对象和集合。对于Map和Array,调用clear()而不是创建新实例。
坑点3:对象池容量设置不当
容量太小会导致频繁创建新对象(命中率低),容量太大会浪费内存。特别是在应用的不同生命周期阶段,对对象的需求量可能差异很大。
正确做法:根据实际业务数据设置初始容量和最大容量。初始容量设为平均并发量的1.5倍,最大容量设为峰值并发量的2倍。启用弹性收缩策略,在空闲时自动缩减池大小。
坑点4:对象池与@State的冲突
如果你把从对象池借出的对象赋值给@State变量,当对象归还到池中并被重置后,@State的UI绑定可能显示错误数据。更严重的是,@State的变更检测机制可能持有对象的引用,阻止对象被正确归还。
正确做法:不要将池化对象直接绑定到@State。应该将池化对象的数据复制到独立的@State变量中,或者使用不可变的数据快照。
坑点5:线程安全问题
ArkTS目前是单线程模型,但在Worker线程和主线程之间传递池化对象时,可能出现竞态条件。一个线程正在使用对象,另一个线程已经把它归还到池中。
正确做法:对象池应该只在单一线程中使用。如果需要跨线程传递数据,使用深拷贝而不是共享池化对象。
坑点6:过度使用对象池
并非所有对象都适合池化。简单值对象(如只包含2-3个基本类型字段的对象)的创建开销极低,使用对象池反而增加了代码复杂度,得不偿失。
正确做法:只在Profiler确认对象创建是性能瓶颈时才引入对象池。优先优化创建开销大的对象(如包含大数组、Map、网络连接的对象)。
五、HarmonyOS 6适配说明
API差异表
| 功能 | HarmonyOS 5 | HarmonyOS 6 | 变更说明 |
|---|---|---|---|
| WeakRef | 支持 | 支持 + 性能优化 | deref()性能提升30% |
| FinalizationRegistry | 支持 | 支持 + 回调增强 | 新增heldValue参数 |
| SharedArrayBuffer | 不支持 | 支持 | 可用于跨Worker共享池 |
| 内存分配追踪 | 不支持 | profiler.trackAllocations() |
新增分配追踪API |
| TaskPool | 基础支持 | 增强 + 对象转移 | 支持对象所有权转移 |
行为变更
-
对象转移语义:HarmonyOS 6的TaskPool支持对象所有权转移(Transfer),可以将对象从一个线程转移到另一个线程而不需要深拷贝。这对对象池的跨线程使用提供了原生支持。
-
SharedArrayBuffer:HarmonyOS 6新增了
SharedArrayBuffer支持,可以在多个Worker之间共享内存。这使得跨线程对象池的实现更加高效。 -
GC与对象池的协作优化:HarmonyOS 6的GC在标记阶段会跳过被对象池持有的对象(如果池标记为"pinned"),减少了不必要的扫描开销。
适配代码
// HarmonyOS 6 跨Worker对象池适配
class CrossWorkerPool<T extends Poolable> {
private localPool: ObjectPool<T>
private sharedBuffer: SharedArrayBuffer | null = null
private poolLock: Int32Array | null = null
constructor(config: ObjectPoolConfig<T>) {
this.localPool = new ObjectPool<T>(config)
// HarmonyOS 6: 尝试创建共享内存用于跨Worker同步
try {
if (typeof SharedArrayBuffer !== 'undefined') {
this.sharedBuffer = new SharedArrayBuffer(1024)
this.poolLock = new Int32Array(this.sharedBuffer)
// 初始化锁状态
Atomics.store(this.poolLock, 0, 0)
}
} catch (e) {
console.warn('[CrossWorkerPool] SharedArrayBuffer不可用,降级为本地池')
}
}
// 线程安全的借出
borrow(): T {
this.acquireLock()
try {
return this.localPool.borrow()
} finally {
this.releaseLock()
}
}
// 线程安全的归还
return(obj: T): void {
this.acquireLock()
try {
this.localPool.return(obj)
} finally {
this.releaseLock()
}
}
// 获取锁
private acquireLock(): void {
if (this.poolLock) {
// 使用Atomics实现简单的自旋锁
while (Atomics.compareExchange(this.poolLock, 0, 0, 1) !== 0) {
// 自旋等待
}
}
}
// 释放锁
private releaseLock(): void {
if (this.poolLock) {
Atomics.store(this.poolLock, 0, 0)
}
}
// 获取状态
getStatus(): PoolStatus {
return this.localPool.getStatus()
}
}
六、总结
三维度评价表
| 维度 | 评分 | 说明 |
|---|---|---|
| 重要性 | ⭐⭐⭐⭐ | 对象池是解决高频对象创建问题的利器,但需要根据场景判断是否使用 |
| 复杂度 | ⭐⭐⭐ | 基本原理简单,但容量管理、状态重置、线程安全等细节需要仔细处理 |
| 实用性 | ⭐⭐⭐⭐⭐ | 在消息处理、事件分发、列表渲染等高频场景中效果显著 |
核心收获:
- 对象池的核心思想是"预先创建、按需借出、用完归还",通过复用对象减少GC压力
- 通用对象池需要支持容量管理(固定/动态/弹性)、状态重置、统计监控等核心功能
- 消息池、事件池、组件池是鸿蒙应用中最常见的三种对象池应用场景
- 对象池的关键风险是忘记归还和重置不彻底,必须使用
try-finally模式 - 不是所有对象都适合池化——只在Profiler确认瓶颈后才引入对象池
一句话总结:对象池就像一个精明的仓库管理员——它知道什么时候该备货、什么时候该清仓、什么时候该拒绝出借。掌握了对象池的设计与使用,你就掌握了在对象创建与GC之间找到最优平衡点的关键能力。
- 点赞
- 收藏
- 关注作者
评论(0)