9 第8章 性能优化
9.1 8.1 UI渲染性能
9.1.1 8.1.1 组件渲染机制
HarmonyOS使用ArkUI框架进行UI开发,其渲染引擎基于声明式UI范式。理解组件渲染机制是进行UI性能优化的基础。
ArkUI的渲染流程可以分为以下几个阶段:
- 构建阶段(Build):框架执行组件的
build()方法,生成虚拟节点树(VDOM)。 - 差异计算(Diff):对比新旧虚拟节点树,计算需要更新的最小变更集。
- 布局计算(Layout):根据节点属性和约束条件,计算每个节点的位置和尺寸。
- 绘制阶段(Paint):将布局结果转换为GPU可执行的绘制指令。
- 合成上屏(Composite):GPU执行绘制指令,将最终画面显示在屏幕上。
每一帧的目标是在16.67ms内完成以上所有步骤(对应60fps刷新率),否则会出现掉帧卡顿。
// 组件渲染生命周期
@Component
struct RenderDemo {
@State count: number = 0
// 组件创建时调用,仅执行一次
aboutToAppear(): void {
console.info('组件即将出现')
}
// 组件渲染完成后调用
onDidBuild(): void {
console.info('组件渲染完成')
}
// 组件销毁时调用
aboutToDisappear(): void {
console.info('组件即将销毁')
}
build() {
Column() {
Text(`计数: ${this.count}`)
.fontSize(20)
Button('增加')
.onClick(() => {
this.count++ // 状态变化触发重新渲染
})
}
}
}9.1.2 8.1.2 布局优化
布局优化是UI性能优化的首要环节。不合理的布局结构会导致过多的测量和布局计算。
减少布局嵌套
深层嵌套的布局会显著增加布局计算的复杂度。应尽量使用扁平化布局。
// 不推荐:深层嵌套
@Component
struct BadLayout {
build() {
Column() { // 第1层
Row() { // 第2层
Column() { // 第3层
Row() { // 第4层 - 不必要的嵌套
Text('用户名')
TextInput()
}
Row() { // 第4层
Text('密码')
TextInput()
}
}
}
}
}
}
// 推荐:扁平化布局
@Component
struct GoodLayout {
build() {
Column({ space: 16 }) {
Row({ space: 12 }) {
Text('用户名').width(80)
TextInput().layoutWeight(1)
}
Row({ space: 12 }) {
Text('密码').width(80)
TextInput().layoutWeight(1)
}
}
.padding(16)
}
}使用相对布局替代嵌套线性布局
// 使用Stack和相对定位减少嵌套
@Component
struct RelativeDemo {
build() {
Stack({ alignContent: Alignment.TopStart }) {
// 背景层
Image($r('app.media.background'))
.width('100%')
.height(200)
// 内容层 - 使用margin定位而非嵌套容器
Column() {
Text('标题')
.fontSize(24)
.fontColor(Color.White)
.margin({ top: 60, left: 16 })
Text('副标题')
.fontSize(14)
.fontColor(Color.White)
.margin({ top: 8, left: 16 })
}
.width('100%')
}
}
}合理使用layoutWeight
// 使用layoutWeight实现弹性布局,避免硬编码尺寸
@Component
struct FlexLayoutDemo {
build() {
Row() {
// 左侧固定宽度
Image($r('app.media.avatar'))
.width(48)
.height(48)
.borderRadius(24)
.margin({ right: 12 })
// 中间自适应
Column() {
Text('用户名').fontSize(16).fontWeight(FontWeight.Medium)
Text('个性签名').fontSize(12).fontColor(Color.Gray)
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
// 右侧固定宽度
Button('关注')
.width(64)
.height(32)
}
.width('100%')
.padding(12)
}
}9.1.3 8.1.3 按需渲染与局部刷新
ArkUI框架通过@State、@Prop、@Link等状态变量实现精确的局部刷新。只有依赖了变化状态变量的组件才会重新渲染。
// 精确控制刷新范围
@Component
struct ChildComponent {
@Prop title: string // @Prop 仅在父组件传入值变化时刷新
aboutToAppear(): void {
console.info('ChildComponent aboutToAppear')
}
build() {
Column() {
Text(this.title)
}
}
}
@Component
struct ParentComponent {
@State title: string = '初始标题'
@State unrelatedData: number = 0
build() {
Column() {
// 只有title变化时,ChildComponent才会重新渲染
ChildComponent({ title: this.title })
// 这个按钮的变化不会影响ChildComponent
Button(`无关计数: ${this.unrelatedData}`)
.onClick(() => {
this.unrelatedData++ // 仅刷新Button,不刷新ChildComponent
})
Button('修改标题')
.onClick(() => {
this.title = '新标题' // 仅刷新ChildComponent
})
}
}
}使用@Observed和@ObjectLink优化对象属性刷新
@Observed
class TaskItem {
id: string
title: string
isCompleted: boolean
constructor(id: string, title: string, isCompleted: boolean = false) {
this.id = id
this.title = title
this.isCompleted = isCompleted
}
}
// 子组件仅监听特定属性的变化
@Component
struct TaskItemView {
@ObjectLink task: TaskItem
build() {
Row() {
Checkbox()
.select(this.task.isCompleted)
.onChange((checked: boolean) => {
this.task.isCompleted = checked // 仅刷新当前项
})
Text(this.task.title)
.decoration({
type: this.task.isCompleted ? TextDecorationType.LineThrough : TextDecorationType.None
})
.fontColor(this.task.isCompleted ? Color.Gray : Color.Black)
}
.width('100%')
.padding(12)
}
}
@Component
struct TaskList {
@State tasks: TaskItem[] = [
new TaskItem('1', '学习ArkTS'),
new TaskItem('2', '完成项目'),
new TaskItem('3', '编写测试')
]
build() {
List() {
ForEach(this.tasks, (task: TaskItem) => {
ListItem() {
TaskItemView({ task: task })
}
}, (task: TaskItem) => task.id) // 使用唯一key
}
}
}9.1.4 8.1.4 组件复用(@Reusable)
@Reusable装饰器标记组件可以被复用,避免频繁创建和销毁组件带来的性能开销。这在列表场景中效果尤为显著。
// 使用@Reusable标记可复用组件
@Reusable
@Component
struct ProductCard {
@State product: Product | null = null
// 组件复用时回调,更新数据
aboutToReuse(params: Record<string, Object>): void {
this.product = params.product as Product
console.info(`组件被复用,新产品: ${this.product?.name}`)
}
build() {
if (this.product) {
Row() {
Image(this.product.imageUrl)
.width(80)
.height(80)
.borderRadius(8)
.objectFit(ImageFit.Cover)
Column() {
Text(this.product.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(`¥${this.product.price.toFixed(2)}`)
.fontSize(14)
.fontColor(Color.Red)
.margin({ top: 4 })
Text(`已售 ${this.product.soldCount} 件`)
.fontSize(12)
.fontColor(Color.Gray)
.margin({ top: 2 })
}
.layoutWeight(1)
.margin({ left: 12 })
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(12)
.backgroundColor(Color.White)
.borderRadius(12)
}
}
}
interface Product {
id: string
name: string
price: number
imageUrl: string
soldCount: number
}9.1.5 8.1.5 列表性能优化
列表是应用中最常见的UI组件,其性能直接影响用户体验。LazyForEach配合唯一key是列表性能优化的核心方案。
// 实现IDataSource接口用于LazyForEach
class ProductDataSource implements IDataSource {
private products: Product[] = []
private listeners: DataChangeListener[] = []
totalCount(): number {
return this.products.length
}
getData(index: number): Product {
return this.products[index]
}
// 追加数据
appendData(newProducts: Product[]): void {
const startIndex = this.products.length
this.products.push(...newProducts)
// 通知框架新增数据
for (const listener of this.listeners) {
listener.onDataAdd(startIndex, newProducts.length)
}
}
// 更新单条数据
updateItem(index: number, product: Product): void {
this.products[index] = product
for (const listener of this.listeners) {
listener.onDataChange(index)
}
}
// 删除数据
removeItem(index: number): void {
this.products.splice(index, 1)
for (const listener of this.listeners) {
listener.onDataDelete(index, 1)
}
}
registerDataChangeListener(listener: DataChangeListener): void {
this.listeners.push(listener)
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const index = this.listeners.indexOf(listener)
if (index >= 0) {
this.listeners.splice(index, 1)
}
}
}
// 高性能列表组件
@Component
struct OptimizedProductList {
private dataSource: ProductDataSource = new ProductDataSource()
private isLoadingMore: boolean = false
aboutToAppear(): void {
// 初始加载
this.loadProducts()
}
async loadProducts(): Promise<void> {
const products = await fetchProducts(0, 20)
this.dataSource.appendData(products)
}
async loadMore(): Promise<void> {
if (this.isLoadingMore) return
this.isLoadingMore = true
try {
const products = await fetchProducts(this.dataSource.totalCount(), 20)
this.dataSource.appendData(products)
} finally {
this.isLoadingMore = false
}
}
build() {
List({ space: 8 }) {
// 使用LazyForEach实现按需加载
LazyForEach(this.dataSource, (product: Product, index: number) => {
ListItem() {
ProductCard({ product: product })
}
.onAppear(() => {
// 接近底部时触发加载更多
if (index >= this.dataSource.totalCount() - 5) {
this.loadMore()
}
})
}, (product: Product) => product.id) // 唯一key,至关重要
}
.width('100%')
.height('100%')
.cachedCount(5) // 缓存屏幕外5个item
.divider({
strokeWidth: 0.5,
color: '#F0F0F0',
startMargin: 12,
endMargin: 12
})
}
}
// 模拟网络请求
async function fetchProducts(offset: number, limit: number): Promise<Product[]> {
return []
}列表优化的关键要点:
- 必须使用唯一且稳定的key:key用于Diff算法识别列表项身份,使用不稳定的key(如index)会导致不必要的组件重建。
- 使用LazyForEach替代ForEach:LazyForEach仅在item进入可视区域时才创建组件,大幅减少初始渲染开销。
- 设置合理的cachedCount:缓存适量的屏幕外item,平衡滚动流畅度和内存占用。
- 使用@Reusable复用组件:减少item创建和销毁的开销。
9.2 8.2 启动性能优化
9.2.1 8.2.1 冷启动/热启动优化
应用启动分为冷启动和热启动两种模式:
- 冷启动:应用进程不存在,需要完整创建进程、加载代码、初始化框架。
- 热启动:应用进程已存在但Activity被回收,需要重建UI。
冷启动耗时远大于热启动,是优化的重点。
// EntryAbility启动优化
import { UIAbility, Want, AbilityConstant } from '@kit.AbilityKit'
import { window } from '@kit.ArkUI'
export default class EntryAbility extends UIAbility {
private windowStage: window.WindowStage | null = null
async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
// 1. 仅做最小初始化,避免onCreate中执行耗时操作
console.info('Ability onCreate')
// 2. 预加载关键数据(异步,不阻塞启动)
this.preloadCriticalData()
// 3. 延迟初始化非关键服务
setTimeout(() => {
this.initNonCriticalServices()
}, 0)
}
async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
this.windowStage = windowStage
// 1. 设置启动页(Splash Screen)
await windowStage.setWindowLayoutFullScreen(true)
// 2. 加载首页UI
windowStage.loadContent('pages/Index', (err) => {
if (err) {
console.error(`页面加载失败: ${err.message}`)
return
}
console.info('首页加载完成')
})
}
// 预加载关键数据
private async preloadCriticalData(): Promise<void> {
// 并行预加载多个数据源
const [userConfig, appConfig] = await Promise.all([
this.loadUserConfig(),
this.loadAppConfig()
])
}
// 延迟初始化非关键服务
private initNonCriticalServices(): void {
// 日志上报、性能监控等非关键服务
// 在首屏渲染完成后初始化
}
private async loadUserConfig(): Promise<object> {
return {}
}
private async loadAppConfig(): Promise<object> {
return {}
}
}9.2.2 8.2.2 应用启动流程分析
HarmonyOS应用启动流程包含以下阶段:
- 进程创建阶段:系统创建应用进程,加载运行时环境。
- Ability创建阶段:框架创建UIAbility实例,执行
onCreate回调。 - Window创建阶段:创建窗口,执行
onWindowStageCreate回调。 - 页面加载阶段:加载首页UI资源,执行组件
build()方法。 - 首帧渲染阶段:完成首屏数据加载和UI渲染。
// 启动耗时监控
class StartupMonitor {
private static startTime: number = 0
private static milestones: Map<string, number> = new Map()
static markStart(): void {
StartupMonitor.startTime = Date.now()
}
static mark(milestoneName: string): void {
const elapsed = Date.now() - StartupMonitor.startTime
StartupMonitor.milestones.set(milestoneName, elapsed)
console.info(`[启动监控] ${milestoneName}: ${elapsed}ms`)
}
static report(): void {
const report: Record<string, number> = {}
for (const [name, time] of StartupMonitor.milestones) {
report[name] = time
}
// 上报到监控平台
console.info(`[启动监控报告] ${JSON.stringify(report)}`)
}
}
// 在启动流程中打点
export default class EntryAbility extends UIAbility {
async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
StartupMonitor.markStart()
StartupMonitor.mark('onCreate')
// ...
}
async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
StartupMonitor.mark('onWindowStageCreate')
windowStage.loadContent('pages/Index', (err) => {
if (!err) {
StartupMonitor.mark('loadContent_done')
StartupMonitor.report()
}
})
}
}9.2.3 8.2.3 延迟加载策略
将非首屏必需的资源和逻辑延迟加载,是降低启动耗时的有效手段。
// 路由级别的延迟加载
// 使用router进行页面懒加载
import { router } from '@kit.ArkUI'
// 在首页中,非首屏模块延迟加载
@Component
struct HomePage {
@State isModuleLoaded: boolean = false
@State recommendationData: object[] = []
aboutToAppear(): void {
// 首屏数据优先加载
this.loadEssentialData()
// 非首屏数据延迟加载
setTimeout(() => {
this.loadRecommendation()
}, 500) // 延迟500ms
}
async loadEssentialData(): Promise<void> {
// 加载首屏必需数据
}
async loadRecommendation(): Promise<void> {
// 延迟加载推荐数据
this.recommendationData = await fetchRecommendations()
this.isModuleLoaded = true
}
build() {
Column() {
// 首屏内容 - 立即渲染
BannerSection()
CategorySection()
// 推荐模块 - 延迟渲染
if (this.isModuleLoaded) {
RecommendationSection({ data: this.recommendationData })
} else {
// 占位骨架屏
SkeletonPlaceholder()
}
}
}
}
// 骨架屏组件
@Component
struct SkeletonPlaceholder {
build() {
Column({ space: 12 }) {
ForEach([1, 2, 3], () => {
Row() {
Column()
.width(80)
.height(80)
.borderRadius(8)
.backgroundColor('#F0F0F0')
Column({ space: 8 }) {
Column()
.width('60%')
.height(16)
.borderRadius(4)
.backgroundColor('#F0F0F0')
Column()
.width('40%')
.height(12)
.borderRadius(4)
.backgroundColor('#F0F0F0')
}
.layoutWeight(1)
}
.width('100%')
.padding(12)
})
}
}
}9.2.4 8.2.4 预加载技术
预加载技术可以在用户操作之前提前加载可能需要的资源。
// 页面预加载管理器
class PagePreloader {
private static preloadQueue: string[] = []
private static isPreloading: boolean = false
// 在首页加载完成后预加载二级页面
static startPreload(pages: string[]): void {
PagePreloader.preloadQueue = [...pages]
PagePreloader.preloadNext()
}
private static async preloadNext(): Promise<void> {
if (PagePreloader.preloadQueue.length === 0 || PagePreloader.isPreloading) {
return
}
PagePreloader.isPreloading = true
const page = PagePreloader.preloadQueue.shift()!
try {
// 预加载页面资源
await router.preloadPage({
url: page
})
console.info(`预加载页面成功: ${page}`)
} catch (error) {
console.warn(`预加载页面失败: ${page}`)
} finally {
PagePreloader.isPreloading = false
// 继续预加载下一个页面
PagePreloader.preloadNext()
}
}
}
// 使用示例
@Component
struct HomePage {
aboutToAppear(): void {
// 首屏渲染完成后预加载常用页面
setTimeout(() => {
PagePreloader.startPreload([
'pages/ProductDetail',
'pages/ShoppingCart',
'pages/UserCenter'
])
}, 2000)
}
build() {
// 首页内容...
Column() {}
}
}9.2.5 8.2.5 启动耗时测量工具
// 启动性能分析工具
class StartupProfiler {
private phases: StartupPhase[] = []
private currentPhase: string = ''
private phaseStartTime: number = 0
startPhase(phaseName: string): void {
if (this.currentPhase) {
this.endPhase()
}
this.currentPhase = phaseName
this.phaseStartTime = Date.now()
}
endPhase(): void {
const duration = Date.now() - this.phaseStartTime
this.phases.push({
name: this.currentPhase,
startTime: this.phaseStartTime,
duration: duration
})
this.currentPhase = ''
}
getReport(): StartupReport {
const totalDuration = this.phases.reduce((sum, p) => sum + p.duration, 0)
const bottleneck = this.phases.reduce((max, p) =>
p.duration > max.duration ? p : max
)
return {
phases: this.phases,
totalDuration: totalDuration,
bottleneck: bottleneck,
suggestions: this.generateSuggestions()
}
}
private generateSuggestions(): string[] {
const suggestions: string[] = []
for (const phase of this.phases) {
if (phase.name === 'onCreate' && phase.duration > 200) {
suggestions.push('onCreate耗时超过200ms,建议检查是否有同步IO操作')
}
if (phase.name === 'loadContent' && phase.duration > 500) {
suggestions.push('页面加载耗时超过500ms,建议优化首屏组件复杂度')
}
if (phase.name === 'dataLoad' && phase.duration > 1000) {
suggestions.push('数据加载耗时超过1s,建议使用缓存或预加载')
}
}
return suggestions
}
}
interface StartupPhase {
name: string
startTime: number
duration: number
}
interface StartupReport {
phases: StartupPhase[]
totalDuration: number
bottleneck: StartupPhase
suggestions: string[]
}9.3 8.3 内存管理
9.3.1 8.3.1 ArkTS内存模型
ArkTS运行在Ark虚拟机上,采用自动内存管理机制。理解内存模型有助于编写高效的代码。
内存主要分为以下区域:
- 栈(Stack):存储局部变量、函数调用帧。自动分配和释放,速度快但空间有限。
- 堆(Heap):存储对象实例。由GC(垃圾回收器)管理,空间大但分配和回收开销较高。
- Native内存:存储图片、音视频等大对象。需要手动管理或使用NAPI接口。
// 内存使用示例
@Component
struct MemoryDemo {
// 这些变量存储在栈上(基本类型)或堆上(对象类型)
@State count: number = 0 // 基本类型,栈存储
@State name: string = '' // 字符串对象,堆存储
@State items: number[] = [] // 数组对象,堆存储
private largeData: ArrayBuffer | null = null // 大对象
processData(): void {
// 局部变量在函数返回后自动释放
const tempArray: number[] = []
for (let i = 0; i < 10000; i++) {
tempArray.push(i)
}
// tempArray在函数结束后变为垃圾,等待GC回收
}
// 大对象需要手动释放
loadLargeFile(): void {
this.largeData = new ArrayBuffer(50 * 1024 * 1024) // 50MB
// 使用完毕后应置为null
}
releaseLargeFile(): void {
this.largeData = null // 解除引用,允许GC回收
}
build() {
Column() {
Button('处理数据').onClick(() => this.processData())
Button('释放大对象').onClick(() => this.releaseLargeFile())
}
}
}9.3.2 8.3.2 内存泄漏检测与预防
内存泄漏是应用性能退化的常见原因。以下是常见的内存泄漏场景和预防方法。
// 场景1:未清理的定时器
@Component
struct TimerLeakDemo {
private timerId: number = -1
aboutToAppear(): void {
this.timerId = setInterval(() => {
// 如果组件销毁后定时器仍在运行,会导致内存泄漏
this.updateData()
}, 1000) as number
}
// 正确做法:在组件销毁时清理定时器
aboutToDisappear(): void {
if (this.timerId !== -1) {
clearInterval(this.timerId)
this.timerId = -1
}
}
updateData(): void {
// 更新数据
}
build() {
Column() {}
}
}
// 场景2:未取消的事件监听
@Component
struct EventListenerLeakDemo {
aboutToAppear(): void {
// 注册全局事件监听
EventBus.getInstance().on('data_updated', this.handleDataUpdate)
}
// 正确做法:在组件销毁时取消监听
aboutToDisappear(): void {
EventBus.getInstance().off('data_updated', this.handleDataUpdate)
}
handleDataUpdate = (data: object): void => {
// 处理数据更新
}
build() {
Column() {}
}
}
// 场景3:闭包持有大对象引用
class DataProcessor {
private callback: (() => void) | null = null
// 不推荐:闭包持有大对象
processWithClosure(largeData: ArrayBuffer): void {
this.callback = () => {
// 闭包持有largeData的引用,即使process完成也不会释放
console.info(`数据大小: ${largeData.byteLength}`)
}
}
// 推荐:显式传递需要的值
processExplicitly(largeData: ArrayBuffer): void {
const dataSize = largeData.byteLength // 只捕获需要的值
this.callback = () => {
console.info(`数据大小: ${dataSize}`)
}
}
destroy(): void {
this.callback = null // 释放回调引用
}
}9.3.3 8.3.3 图片内存优化
图片是应用中最常见的内存消耗源。合理的图片处理策略可以显著降低内存占用。
// 图片加载优化
@Component
struct OptimizedImage {
@State imageUrl: string = ''
build() {
// 优化1:指定明确的尺寸,避免加载原图
Image(this.imageUrl)
.width(100)
.height(100)
.objectFit(ImageFit.Cover) // 裁剪适配
.interpolation(ImageInterpolation.Low) // 低质量插值,减少CPU开销
.alt($r('app.media.placeholder')) // 占位图
// 优化2:列表中使用合适尺寸的图片
// 在实际项目中,应根据显示尺寸请求对应分辨率的图片
}
}
// 图片缓存管理器
class ImageCacheManager {
private static instance: ImageCacheManager | null = null
private memoryCache: Map<string, PixelMap> = new Map()
private maxCacheSize: number = 50 // 最多缓存50张图片
static getInstance(): ImageCacheManager {
if (!ImageCacheManager.instance) {
ImageCacheManager.instance = new ImageCacheManager()
}
return ImageCacheManager.instance
}
// 获取缓存的图片
getCachedImage(url: string): PixelMap | null {
const cached = this.memoryCache.get(url)
if (cached) {
return cached
}
return null
}
// 缓存图片
cacheImage(url: string, pixelMap: PixelMap): void {
// 缓存满时淘汰最早的
if (this.memoryCache.size >= this.maxCacheSize) {
const firstKey = this.memoryCache.keys().next().value
if (firstKey) {
const oldPixelMap = this.memoryCache.get(firstKey)
oldPixelMap?.release() // 释放PixelMap资源
this.memoryCache.delete(firstKey)
}
}
this.memoryCache.set(url, pixelMap)
}
// 清空缓存
clearCache(): void {
for (const pixelMap of this.memoryCache.values()) {
pixelMap.release()
}
this.memoryCache.clear()
}
}
// 带降采样的图片加载
async function loadDecimatedImage(
context: Context,
resourceId: number,
targetWidth: number,
targetHeight: number
): Promise<PixelMap> {
const resourceManager = context.resourceManager
const buffer = await resourceManager.getMediaContent(resourceId)
const imageSource = image.createImageSource(buffer)
// 使用解码选项进行降采样
const decodingOptions: image.DecodingOptions = {
editable: false,
desiredPixelFormat: 3, // RGBA_8888
desiredSize: {
width: targetWidth,
height: targetHeight
},
// 按比例降采样,减少内存占用
sampleSize: calculateSampleSize(buffer, targetWidth, targetHeight)
}
const pixelMap = await imageSource.createPixelMap(decodingOptions)
imageSource.release()
return pixelMap
}
function calculateSampleSize(
buffer: ArrayBuffer,
targetWidth: number,
targetHeight: number
): number {
// 计算合适的采样率
return 1 // 简化示例
}9.3.4 8.3.4 大对象管理
对于大对象(如大型数组、文件缓冲区等),需要特别注意内存管理。
// 大对象池
class ObjectPool<T> {
private pool: T[] = []
private maxSize: number
private factory: () => T
private reset: (obj: T) => void
constructor(maxSize: number, factory: () => T, reset: (obj: T) => void) {
this.maxSize = maxSize
this.factory = factory
this.reset = reset
}
acquire(): T {
if (this.pool.length > 0) {
return this.pool.pop()!
}
return this.factory()
}
release(obj: T): void {
if (this.pool.length < this.maxSize) {
this.reset(obj)
this.pool.push(obj)
}
// 超过池容量,直接丢弃让GC回收
}
clear(): void {
this.pool = []
}
}
// 使用示例:ArrayBuffer对象池
const bufferPool = new ObjectPool<ArrayBuffer>(
10,
() => new ArrayBuffer(1024 * 1024), // 创建1MB缓冲区
(buffer: ArrayBuffer) => {
// 重置缓冲区(清零)
new Uint8Array(buffer).fill(0)
}
)
// 获取缓冲区
const buffer = bufferPool.acquire()
// 使用缓冲区...
// 释放回池中
bufferPool.release(buffer)9.3.5 8.3.5 内存回收策略与资源释放
// 资源管理器 - 统一管理应用中的各类资源
class ResourceManager {
private static instance: ResourceManager | null = null
private resources: Map<string, Disposable> = new Map()
static getInstance(): ResourceManager {
if (!ResourceManager.instance) {
ResourceManager.instance = new ResourceManager()
}
return ResourceManager.instance
}
// 注册可释放资源
register(id: string, resource: Disposable): void {
this.resources.set(id, resource)
}
// 释放指定资源
async dispose(id: string): Promise<void> {
const resource = this.resources.get(id)
if (resource) {
await resource.dispose()
this.resources.delete(id)
}
}
// 释放所有资源
async disposeAll(): Promise<void> {
for (const [id, resource] of this.resources) {
try {
await resource.dispose()
} catch (error) {
console.error(`释放资源 ${id} 失败: ${(error as Error).message}`)
}
}
this.resources.clear()
}
// 内存警告处理
onMemoryWarning(): void {
console.warn('收到内存警告,开始清理缓存')
// 清理非关键资源
this.clearCaches()
}
private clearCaches(): void {
// 清理图片缓存、数据缓存等
ImageCacheManager.getInstance().clearCache()
}
}
interface Disposable {
dispose(): Promise<void>
}9.4 8.4 功耗优化
9.4.1 8.4.1 后台任务管理
HarmonyOS对后台任务有严格的限制,合理使用后台任务API是功耗优化的关键。
import { backgroundTaskManager } from '@kit.BackgroundTasksKit'
// 后台任务管理器
class BackgroundTaskManager {
// 启动短时任务(最长3分钟)
static async startShortTask(taskName: string, taskFn: () => Promise<void>): Promise<void> {
const shortRequest = new backgroundTaskManager.ShortTimeRequest('dataTransfer')
shortRequest.serviceExtension = {
packageName: 'com.example.app',
abilityName: 'BackgroundAbility'
}
try {
await backgroundTaskManager.startShortTime(shortRequest)
await taskFn()
await backgroundTaskManager.stopShortTime(shortRequest)
} catch (error) {
console.error(`短时任务 ${taskName} 执行失败`)
await backgroundTaskManager.stopShortTime(shortRequest)
}
}
// 启动长时任务(需要声明权限)
static async startLongTask(
taskType: backgroundTaskManager.WorkMode,
taskFn: () => Promise<void>
): Promise<void> {
const longRequest = new backgroundTaskManager.LongTimeRequest(taskType)
try {
await backgroundTaskManager.startLongTime(longRequest)
await taskFn()
} finally {
await backgroundTaskManager.stopLongTime(longRequest)
}
}
}
// 使用示例:后台数据同步
async function syncDataInBackground(): Promise<void> {
await BackgroundTaskManager.startShortTask('dataSync', async () => {
const syncManager = new SyncManager()
await syncManager.incrementalSync('orders')
})
}9.4.2 8.4.2 定位服务优化
定位服务是功耗大户,需要合理使用定位策略。
import { geoLocationManager } from '@kit.LocationKit'
// 定位服务优化管理器
class LocationOptimizer {
private isLocating: boolean = false
// 场景1:需要精确定位(如导航)
async startPreciseLocation(callback: (location: geoLocationManager.Location) => void): Promise<void> {
const request: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.Accuracy,
scenario: geoLocationManager.LocationRequestScenario.Navigation,
interval: 1000, // 1秒更新一次
maxAccuracy: 10 // 精度10米
}
this.isLocating = true
await geoLocationManager.on('location', request, callback)
}
// 场景2:只需大致位置(如附近推荐)
async startRoughLocation(callback: (location: geoLocationManager.Location) => void): Promise<void> {
const request: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.LocatingMode,
scenario: geoLocationManager.LocationRequestScenario.SceneBased,
interval: 60000, // 60秒更新一次
maxAccuracy: 1000 // 精度1000米
}
this.isLocating = true
await geoLocationManager.on('location', request, callback)
}
// 场景3:单次定位(如签到)
async getSingleLocation(): Promise<geoLocationManager.Location> {
const request: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.Accuracy,
scenario: geoLocationManager.LocationRequestScenario.Traffic,
maxAccuracy: 50,
interval: 0 // 单次定位
}
return await geoLocationManager.getCurrentLocation(request)
}
// 停止定位
async stopLocation(callback: (location: geoLocationManager.Location) => void): Promise<void> {
await geoLocationManager.off('location', callback)
this.isLocating = false
}
}9.4.3 8.4.3 网络请求优化
网络请求是主要的功耗来源之一。通过批量请求和缓存策略可以显著降低功耗。
// 批量请求合并
class BatchRequestOptimizer {
private pendingRequests: Map<string, {
resolve: (value: object) => void,
reject: (reason: Error) => void
}> = new Map()
private batchTimer: number = -1
private batchDelay: number = 100 // 100ms内的请求合并
// 发起请求(自动合并)
async request(url: string, params: object): Promise<object> {
return new Promise((resolve, reject) => {
const key = `${url}:${JSON.stringify(params)}`
this.pendingRequests.set(key, { resolve, reject })
if (this.batchTimer === -1) {
this.batchTimer = setTimeout(() => this.flushBatch(), this.batchDelay) as number
}
})
}
// 批量发送
private async flushBatch(): Promise<void> {
const requests = Array.from(this.pendingRequests.entries())
this.pendingRequests.clear()
this.batchTimer = -1
if (requests.length === 0) return
try {
// 合并为单个批量请求
const batchPayload = requests.map(([key]) => {
const [url, paramsStr] = key.split(':')
return { url, params: JSON.parse(paramsStr) }
})
const results = await this.sendBatchRequest(batchPayload)
// 分发结果
for (let i = 0; i < requests.length; i++) {
const { resolve } = requests[i][1]
resolve(results[i])
}
} catch (error) {
for (const [, { reject }] of requests) {
reject(error as Error)
}
}
}
private async sendBatchRequest(batch: object[]): Promise<object[]> {
// 发送批量请求到服务端
return []
}
}
// 网络缓存策略
class NetworkCacheStrategy {
// 缓存优先策略
async cacheFirst<T>(key: string, fetchFn: () => Promise<T>, ttl: number): Promise<T> {
// 先查缓存
const cached = await this.getFromCache<T>(key)
if (cached && !this.isExpired(cached.timestamp, ttl)) {
// 后台静默更新缓存
this.silentRefresh(key, fetchFn)
return cached.data
}
// 缓存未命中或已过期,发起网络请求
const data = await fetchFn()
await this.saveToCache(key, data)
return data
}
// 网络优先策略
async networkFirst<T>(key: string, fetchFn: () => Promise<T>): Promise<T> {
try {
const data = await fetchFn()
await this.saveToCache(key, data)
return data
} catch (error) {
// 网络失败,降级到缓存
const cached = await this.getFromCache<T>(key)
if (cached) {
return cached.data
}
throw error
}
}
private async getFromCache<T>(key: string): Promise<{ data: T; timestamp: number } | null> {
return null
}
private async saveToCache<T>(key: string, data: T): Promise<void> {}
private isExpired(timestamp: number, ttl: number): boolean {
return Date.now() - timestamp > ttl
}
private async silentRefresh<T>(key: string, fetchFn: () => Promise<T>): Promise<void> {
try {
const data = await fetchFn()
await this.saveToCache(key, data)
} catch (error) {
// 静默失败
}
}
}9.4.4 8.4.4 屏幕刷新率管理
根据场景动态调整屏幕刷新率可以节省电量。
import { display } from '@kit.ArkUI'
// 刷新率管理器
class RefreshRateManager {
// 高刷新率场景(动画、游戏)
static async setHighRefreshRate(): Promise<void> {
try {
const defaultDisplay = display.getDefaultDisplaySync()
// 请求高刷新率模式
console.info(`当前刷新率: ${defaultDisplay.refreshRate}Hz`)
} catch (error) {
console.error('设置刷新率失败')
}
}
// 标准刷新率场景(普通浏览)
static async setStandardRefreshRate(): Promise<void> {
// 设置为60Hz标准刷新率
console.info('切换到标准刷新率')
}
// 低刷新率场景(静态页面、阅读)
static async setLowRefreshRate(): Promise<void> {
// 降低刷新率以节省电量
console.info('切换到低刷新率')
}
}9.4.5 8.4.5 传感器使用优化
// 传感器使用优化
class SensorOptimizer {
// 按需注册传感器
private sensorCallbacks: Map<number, object> = new Map()
// 加速度传感器优化
registerAccelerometer(
onShake: () => void,
options?: { threshold?: number; interval?: number }
): void {
const threshold = options?.threshold ?? 15
const interval = options?.interval ?? 200
// 使用较低的采样频率,仅在需要时提高
// sensor.on(sensor.SensorId.ACCELEROMETER, { interval: interval }, (data) => {
// if (Math.abs(data.x) > threshold || Math.abs(data.y) > threshold) {
// onShake()
// }
// })
}
// 页面不可见时自动停止传感器
onPageHidden(): void {
// 取消所有传感器监听
for (const [sensorId] of this.sensorCallbacks) {
// sensor.off(sensorId)
}
this.sensorCallbacks.clear()
}
}9.5 8.5 代码性能优化
9.5.1 8.5.1 算法复杂度优化
选择合适的数据结构和算法是性能优化的根本。
// 不推荐:O(n²) 查找
function findDuplicatesBad(arr: number[]): number[] {
const duplicates: number[] = []
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j] && !duplicates.includes(arr[i])) {
duplicates.push(arr[i])
}
}
}
return duplicates
}
// 推荐:O(n) 使用Set查找
function findDuplicatesGood(arr: number[]): number[] {
const seen = new Set<number>()
const duplicates = new Set<number>()
for (const num of arr) {
if (seen.has(num)) {
duplicates.add(num)
} else {
seen.add(num)
}
}
return Array.from(duplicates)
}
// 字符串拼接优化
// 不推荐:字符串直接拼接(每次创建新字符串)
function joinStringsBad(strings: string[]): string {
let result = ''
for (const s of strings) {
result += s // 每次都创建新字符串对象
}
return result
}
// 推荐:使用数组join
function joinStringsGood(strings: string[]): string {
return strings.join('')
}9.5.2 8.5.2 数据结构选择
// 不同数据结构的性能对比
class DataStructureDemo {
// 场景1:频繁查找 - 使用Map
lookupDemo(): void {
// 不推荐:数组查找 O(n)
const userList: Array<{ id: string; name: string }> = []
const findById = (id: string) => userList.find(u => u.id === id) // O(n)
// 推荐:Map查找 O(1)
const userMap = new Map<string, { id: string; name: string }>()
const findByIdFast = (id: string) => userMap.get(id) // O(1)
}
// 场景2:去重 - 使用Set
deduplicateDemo(): void {
const items = [1, 2, 2, 3, 3, 3, 4, 5]
// 推荐:使用Set去重
const unique = [...new Set(items)]
}
// 场景3:有序数据 - 使用排序数组 + 二分查找
sortedSearchDemo(): void {
const sortedArray = [1, 3, 5, 7, 9, 11, 13, 15]
// 二分查找 O(log n)
function binarySearch(arr: number[], target: number): number {
let left = 0
let right = arr.length - 1
while (left <= right) {
const mid = Math.floor((left + right) / 2)
if (arr[mid] === target) return mid
if (arr[mid] < target) left = mid + 1
else right = mid - 1
}
return -1
}
const index = binarySearch(sortedArray, 7) // 返回3
}
}9.5.3 8.5.3 异步任务编排
合理的异步任务编排可以最大化利用系统资源,减少等待时间。
// 并行执行多个独立任务
async function parallelExecution(): Promise<void> {
const startTime = Date.now()
// 推荐:并行执行独立任务
const [userData, productData, configData] = await Promise.all([
fetchUserData(),
fetchProductData(),
fetchConfigData()
])
console.info(`并行执行耗时: ${Date.now() - startTime}ms`)
}
// 串行执行有依赖的任务
async function sequentialExecution(): Promise<void> {
// 步骤1:先登录
const token = await login('user', 'pass')
// 步骤2:使用Token获取数据
const data = await fetchDataWithToken(token)
// 步骤3:处理数据
const result = await processData(data)
}
// 流水线模式:任务分阶段并行执行
async function pipelineExecution(items: string[]): Promise<object[]> {
// 阶段1:并行解析所有项目
const parsed = await Promise.all(
items.map(item => parseItem(item))
)
// 阶段2:并行验证所有项目
const validated = await Promise.all(
parsed.map(item => validateItem(item))
)
// 阶段3:并行保存所有项目
const results = await Promise.all(
validated.map(item => saveItem(item))
)
return results
}
// 并发限制器:控制同时执行的任务数
async function limitedConcurrency<T>(
tasks: Array<() => Promise<T>>,
maxConcurrency: number
): Promise<T[]> {
const results: T[] = []
const executing: Set<Promise<void>> = new Set()
for (const task of tasks) {
const p = task().then(result => {
results.push(result)
})
executing.add(p)
p.finally(() => executing.delete(p))
// 达到并发上限时等待任意任务完成
if (executing.size >= maxConcurrency) {
await Promise.race(executing)
}
}
await Promise.all(executing)
return results
}
// 模拟函数
async function fetchUserData(): Promise<object> { return {} }
async function fetchProductData(): Promise<object> { return {} }
async function fetchConfigData(): Promise<object> { return {} }
async function login(u: string, p: string): Promise<string> { return '' }
async function fetchDataWithToken(t: string): Promise<object> { return {} }
async function processData(d: object): Promise<object> { return {} }
async function parseItem(item: string): Promise<object> { return {} }
async function validateItem(item: object): Promise<object> { return {} }
async function saveItem(item: object): Promise<object> { return {} }9.5.4 8.5.4 缓存策略
// LRU缓存实现
class LRUCache<K, V> {
private capacity: number
private cache: Map<K, V>
constructor(capacity: number) {
this.capacity = capacity
this.cache = new Map()
}
get(key: K): V | undefined {
const value = this.cache.get(key)
if (value !== undefined) {
// 移到最近使用位置
this.cache.delete(key)
this.cache.set(key, value)
}
return value
}
put(key: K, value: V): void {
if (this.cache.has(key)) {
this.cache.delete(key)
} else if (this.cache.size >= this.capacity) {
// 淘汰最久未使用的
const firstKey = this.cache.keys().next().value
if (firstKey !== undefined) {
this.cache.delete(firstKey)
}
}
this.cache.set(key, value)
}
get size(): number {
return this.cache.size
}
clear(): void {
this.cache.clear()
}
}
// FIFO缓存实现
class FIFOCache<K, V> {
private capacity: number
private cache: Map<K, V>
private order: K[]
constructor(capacity: number) {
this.capacity = capacity
this.cache = new Map()
this.order = []
}
get(key: K): V | undefined {
return this.cache.get(key)
}
put(key: K, value: V): void {
if (this.cache.has(key)) {
this.cache.set(key, value)
return
}
if (this.cache.size >= this.capacity) {
// 淘汰最早插入的
const oldest = this.order.shift()
if (oldest !== undefined) {
this.cache.delete(oldest)
}
}
this.cache.set(key, value)
this.order.push(key)
}
}
// 使用示例
const lruCache = new LRUCache<string, UserProfile>(100)
lruCache.put('user_001', { id: 'user_001', name: '张三' } as UserProfile)
const user = lruCache.get('user_001')
interface UserProfile {
id: string
name: string
}9.5.5 8.5.5 编译优化选项
HarmonyOS的ArkCompiler提供了多种编译优化选项。
// build-profile.json5 中的编译优化配置
{
"app": {
"products": [
{
"name": "release",
"buildOption": {
"strictMode": {
"useNormalizedOHMURL": true
},
"arkOptions": {
"runtimeOnly": {
"sources": [],
"packages": []
},
"byteCodeHar": true
}
},
"compileMode": "esmodule",
"targetSdkVersion": "5.0.0(12)",
"compatibleSdkVersion": "5.0.0(12)",
"runtimeOS": "HarmonyOS"
}
]
}
}9.6 8.6 性能分析工具
9.6.1 8.6.1 DevEco Profiler使用
DevEco Profiler是HarmonyOS官方提供的性能分析工具集,包含多个子工具用于分析不同维度的性能问题。
主要功能模块: - Time Profiler:分析CPU时间消耗,找出耗时函数 - Frame Profiler:分析帧渲染过程,定位掉帧原因 - Allocation Profiler:分析内存分配,检测内存泄漏 - Snapshot Profiler:获取内存快照,分析对象分布 - Trace Viewer:系统级Trace分析,查看多线程执行情况
// 使用HiTraceMeter进行代码级Trace打点
import { hiTraceMeter } from '@kit.PerformanceAnalysisKit'
class TraceDemo {
async loadData(): Promise<void> {
// 开始Trace
hiTraceMeter.startTrace('LoadData', 0)
try {
// 子阶段1:网络请求
hiTraceMeter.startTrace('NetworkRequest', 1)
const data = await this.fetchFromNetwork()
hiTraceMeter.finishTrace('NetworkRequest', 1)
// 子阶段2:数据解析
hiTraceMeter.startTrace('DataParsing', 2)
const parsed = this.parseData(data)
hiTraceMeter.finishTrace('DataParsing', 2)
// 子阶段3:UI更新
hiTraceMeter.startTrace('UIUpdate', 3)
this.updateUI(parsed)
hiTraceMeter.finishTrace('UIUpdate', 3)
} finally {
hiTraceMeter.finishTrace('LoadData', 0)
}
}
async fetchFromNetwork(): Promise<object> { return {} }
parseData(data: object): object { return {} }
updateUI(data: object): void {}
}9.6.2 8.6.2 Frame Profiler分析
Frame Profiler用于分析UI帧渲染性能,帮助定位掉帧和卡顿问题。
// 帧性能监控组件
@Component
struct FrameMonitorDemo {
@State frameStats: FrameStatistics = {
totalFrames: 0,
jankyFrames: 0,
avgFrameTime: 0,
maxFrameTime: 0
}
aboutToAppear(): void {
this.startMonitoring()
}
startMonitoring(): void {
// 使用frameMonitor API监控帧率
// 在DevEco Studio的Frame Profiler中可以可视化查看
}
build() {
Column() {
Text('帧性能统计')
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(`总帧数: ${this.frameStats.totalFrames}`)
Text(`掉帧数: ${this.frameStats.jankyFrames}`)
Text(`平均帧耗时: ${this.frameStats.avgFrameTime.toFixed(2)}ms`)
Text(`最大帧耗时: ${this.frameStats.maxFrameTime.toFixed(2)}ms`)
Text(`掉帧率: ${(this.frameStats.jankyFrames / Math.max(1, this.frameStats.totalFrames) * 100).toFixed(1)}%`)
}
.padding(16)
}
}
interface FrameStatistics {
totalFrames: number
jankyFrames: number
avgFrameTime: number
maxFrameTime: number
}9.6.3 8.6.3 Trace分析工具
// 使用HiLog输出结构化日志,配合Trace工具分析
import { hilog } from '@kit.PerformanceAnalysisKit'
class PerformanceLogger {
private static domain: number = 0x0001
private static tag: string = 'Performance'
static logPerformanceMetric(
metricName: string,
value: number,
unit: string = 'ms'
): void {
hilog.info(
PerformanceLogger.domain,
PerformanceLogger.tag,
`[PERF] ${metricName} = ${value}${unit}`
)
}
static logComponentRenderTime(
componentName: string,
renderTimeMs: number
): void {
hilog.info(
PerformanceLogger.domain,
PerformanceLogger.tag,
`[RENDER] ${componentName}: ${renderTimeMs}ms`
)
}
static logMemoryUsage(): void {
// 获取并记录当前内存使用情况
hilog.info(
PerformanceLogger.domain,
PerformanceLogger.tag,
'[MEMORY] 记录内存使用快照'
)
}
}9.6.4 8.6.4 性能指标监控
// 性能指标收集器
class PerformanceMetricsCollector {
private metrics: Map<string, number[]> = new Map()
// 记录指标
record(metricName: string, value: number): void {
if (!this.metrics.has(metricName)) {
this.metrics.set(metricName, [])
}
this.metrics.get(metricName)!.push(value)
}
// 获取统计信息
getStats(metricName: string): MetricStats | null {
const values = this.metrics.get(metricName)
if (!values || values.length === 0) return null
const sorted = [...values].sort((a, b) => a - b)
return {
count: values.length,
min: sorted[0],
max: sorted[sorted.length - 1],
avg: values.reduce((a, b) => a + b, 0) / values.length,
p50: sorted[Math.floor(sorted.length * 0.5)],
p90: sorted[Math.floor(sorted.length * 0.9)],
p99: sorted[Math.floor(sorted.length * 0.99)]
}
}
// 上报指标
async report(): Promise<void> {
const report: Record<string, MetricStats> = {}
for (const [name] of this.metrics) {
const stats = this.getStats(name)
if (stats) {
report[name] = stats
}
}
// 上报到监控平台
console.info(`[性能报告] ${JSON.stringify(report)}`)
}
}
interface MetricStats {
count: number
min: number
max: number
avg: number
p50: number
p90: number
p99: number
}
// 使用示例
const collector = new PerformanceMetricsCollector()
// 记录页面加载时间
const loadStart = Date.now()
// ... 加载页面
const loadTime = Date.now() - loadStart
collector.record('page_load_time', loadTime)
// 记录列表滚动帧率
collector.record('scroll_fps', 58)9.6.5 8.6.5 性能基线建立
// 性能基线管理器
class PerformanceBaseline {
private baseline: Record<string, BaselineMetric> = {}
// 建立基线
async establishBaseline(): Promise<void> {
const metrics: Record<string, number[]> = {
'cold_start': [],
'page_switch': [],
'list_scroll_fps': [],
'api_response': [],
'memory_usage': []
}
// 多次采样取平均值
for (let i = 0; i < 5; i++) {
metrics['cold_start'].push(await this.measureColdStart())
metrics['page_switch'].push(await this.measurePageSwitch())
metrics['list_scroll_fps'].push(await this.measureScrollFps())
metrics['api_response'].push(await this.measureApiResponse())
metrics['memory_usage'].push(await this.measureMemory())
}
// 计算基线值(取P90)
for (const [name, values] of Object.entries(metrics)) {
const sorted = values.sort((a, b) => a - b)
this.baseline[name] = {
p50: sorted[Math.floor(sorted.length * 0.5)],
p90: sorted[Math.floor(sorted.length * 0.9)],
max: sorted[sorted.length - 1]
}
}
}
// 检查是否超出基线
checkBaseline(metricName: string, value: number): BaselineCheckResult {
const baseline = this.baseline[metricName]
if (!baseline) {
return { status: 'unknown', message: '无基线数据' }
}
if (value > baseline.p90 * 1.5) {
return {
status: 'critical',
message: `严重超标: ${value}ms (基线P90: ${baseline.p90}ms)`
}
}
if (value > baseline.p90) {
return {
status: 'warning',
message: `超出基线: ${value}ms (基线P90: ${baseline.p90}ms)`
}
}
return {
status: 'normal',
message: `正常: ${value}ms (基线P90: ${baseline.p90}ms)`
}
}
// 模拟测量方法
private async measureColdStart(): Promise<number> { return 800 }
private async measurePageSwitch(): Promise<number> { return 200 }
private async measureScrollFps(): Promise<number> { return 58 }
private async measureApiResponse(): Promise<number> { return 300 }
private async measureMemory(): Promise<number> { return 150 }
}
interface BaselineMetric {
p50: number
p90: number
max: number
}
interface BaselineCheckResult {
status: 'normal' | 'warning' | 'critical' | 'unknown'
message: string
}9.7 本章小结
本章系统讲解了HarmonyOS应用性能优化的完整知识体系:
UI渲染性能:深入理解了组件渲染机制,掌握了布局优化、按需刷新、组件复用(@Reusable)和列表性能优化(LazyForEach + 唯一key)等核心技术。
启动性能优化:理解了冷启动和热启动的区别,掌握了延迟加载、预加载、启动耗时测量等优化手段。
内存管理:了解了ArkTS内存模型,掌握了内存泄漏检测与预防、图片内存优化、大对象管理和资源释放最佳实践。
功耗优化:学习了后台任务管理、定位服务优化、网络请求优化、屏幕刷新率管理和传感器使用优化。
代码性能优化:掌握了算法复杂度优化、数据结构选择、异步任务编排、缓存策略(LRU、FIFO)等编码层面的优化技巧。
性能分析工具:熟悉了DevEco Profiler的使用,掌握了Frame Profiler分析、Trace分析、性能指标监控和性能基线建立方法。
9.8 练习题
9.8.1 一、单选题
1. 在HarmonyOS列表性能优化中,LazyForEach的key生成函数应该返回什么?
A. 列表项的索引值(index) B. 列表项的唯一且稳定的标识符 C. 随机生成的字符串 D. 当前时间戳
答案:B
解析: LazyForEach的key用于Diff算法识别列表项的身份变化。使用唯一且稳定的标识符(如数据ID)可以确保框架正确识别列表项的增删改,避免不必要的组件重建。使用index作为key在列表项发生插入或删除时会导致大量不必要的重建。
2. 以下哪种方式最适合优化应用冷启动时间?
A. 在onCreate中初始化所有第三方库 B. 将非首屏必需的初始化逻辑延迟到首屏渲染后执行 C. 增加应用进程优先级 D. 减少页面中的组件数量
答案:B
解析: 延迟加载(Lazy Initialization)是优化冷启动的核心策略。将非首屏必需的初始化逻辑(如第三方SDK、日志系统、推送服务等)延迟到首屏渲染完成后执行,可以显著缩短启动耗时。在onCreate中初始化所有库会增加启动时间。
3. @Reusable装饰器的主要作用是什么?
A. 让组件支持跨页面共享 B. 标记组件可以被列表复用,减少创建和销毁开销 C. 让组件支持多线程渲染 D. 缓存组件的网络请求结果
答案:B
解析: @Reusable装饰器标记组件可以在列表中复用。当列表项滑出可视区域后再滑入时,框架不会重新创建组件,而是复用已有的组件实例并调用aboutToReuse回调更新数据,从而避免频繁的组件创建和销毁。
9.8.2 二、多选题
4. 以下哪些是常见的内存泄漏场景?
A. 未清理的定时器(setInterval) B. 未取消的事件监听 C. 闭包持有大对象引用 D. 使用const声明的局部变量 E. 未释放的PixelMap资源
答案:A、B、C、E
解析: 未清理的定时器会持续持有组件引用;未取消的事件监听会阻止组件被GC回收;闭包持有大对象引用会阻止大对象释放;未释放的PixelMap会占用Native内存。使用const声明的局部变量在函数返回后会自动释放,不会造成内存泄漏。
5. 关于HarmonyOS性能分析工具,以下哪些说法是正确的?
A. DevEco Profiler包含Time Profiler、Frame Profiler等多个子工具 B. Frame Profiler可以分析帧渲染过程中的性能瓶颈 C. hiTraceMeter可以用于代码级别的Trace打点 D. 性能基线只需要建立一次,无需持续维护 E. hilog可以输出结构化日志用于性能分析
答案:A、B、C、E
解析: DevEco Profiler是一个工具集,包含多个子分析工具;Frame Profiler分析帧渲染性能;hiTraceMeter支持代码级Trace打点;hilog输出结构化日志。性能基线需要随版本迭代持续维护和更新,因为功能变化会影响性能表现。
9.8.3 三、判断题
6. 在ArkUI中,修改@State变量会触发所有组件重新渲染。
答案:错误
解析: ArkUI框架实现了精确的依赖追踪。修改@State变量只会触发依赖了该变量的组件重新渲染,不会影响不相关的组件。这是ArkUI性能优化的基础机制。
7. 使用ForEach渲染列表时,如果key使用数组index,在列表项发生插入操作时可能导致性能问题。
答案:正确
解析: 使用index作为key时,插入操作会导致后续所有item的index发生变化,框架会认为这些item都发生了变化,从而触发大量不必要的组件重建。应使用数据本身的唯一标识作为key。
8. LRU缓存和FIFO缓存的淘汰策略相同。
答案:错误
解析: LRU(Least Recently Used)淘汰最久未使用的数据,每次访问都会更新数据的使用时间;FIFO(First In First Out)淘汰最早插入的数据,不考虑后续的访问情况。两者的淘汰策略不同,适用场景也不同。