news 2026/9/26 12:46:27

内存紧张时 HarmonyOS 会告诉应用吗?onMemoryLevel 最小实践【鸿蒙心迹】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
内存紧张时 HarmonyOS 会告诉应用吗?onMemoryLevel 最小实践【鸿蒙心迹】

你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀

全文目录:

    • 前言
    • 一、onMemoryLevel 解决的不是“查剩余内存”
    • 二、先把官方规则和版本变化弄清楚
    • 三、搭一个最小实践:把“可重建缓存”分成三层
    • 四、在 AbilityStage 中处理内存等级
    • 五、别漏掉 module.json5 的 AbilityStage 入口
    • 六、哪些缓存适合释放,哪些数据不能跟着清
    • 七、还有两个容易误解的地方
      • 1. 收到回调,不等于知道自己释放了多少内存
      • 2. onMemoryLevel 不是应用内存泄漏的修复器
    • 八、实际项目可以按这个顺序排查
    • 开发经验总结

前言

应用里的缓存通常是为了用内存换取速度:预取结果、可重新计算的数据、临时索引,都可能长期留在进程里。但系统整体内存开始紧张时,应用如果还按正常状态持有所有非必要资源,就失去了主动收缩的机会。

HarmonyOS 的 Ability Kit 提供了onMemoryLevel()。以AbilityStage为例,当系统决定调整内存时,会把内存压力级别回调给应用,应用可以据此释放不再必要、并且能够重新构建的资源。官方文档明确把AbilityStage、UIAbility和EnvironmentCallback都列为接收内存变化的方式。

这篇文章只做一件事:围绕AbilityStage.onMemoryLevel()搭一个最小实践,把“收到通知之后到底应该清什么、不应该清什么”说明白。

一、onMemoryLevel 解决的不是“查剩余内存”

先把这个接口的定位弄清楚。

onMemoryLevel()不是一个查询“当前还剩多少 MB 内存”的接口。它接收到的是AbilityConstant.MemoryLevel,表达系统当前的内存压力等级。AbilityStage 官方开发指南说明,当系统调整内存时会触发onMemoryLevel(),开发者可以在回调中释放不必要资源。

因此,它更适合解决这样的业务问题:

应用维护了若干用于加速访问的内存缓存。当系统出现内存压力时,根据压力等级逐步丢弃可以重新获得的数据,同时保留用户正在编辑、尚未持久化或业务流程仍然依赖的关键状态。

这里的核心不是“系统帮应用清缓存”,而是系统给出压力信号,具体释放什么仍由应用自己的资源管理策略决定。

这也是为什么onMemoryLevel()最适合与缓存分级一起设计,而不是收到回调之后简单粗暴地执行一次“全清”。

二、先把官方规则和版本变化弄清楚

本文以当前 HarmonyOS 7 开发环境为背景。华为官方的 26.0.0 升级适配说明明确指出,HarmonyOS 7.0 对应 API 26.0.0,并建议开发者基于 26.0.0 开发套件完成升级适配。

AbilityStage 属于 Stage 模型中的模块级组件容器。一个 AbilityStage 实例对应一个模块;默认工程不会自动生成 AbilityStage,需要使用时可以自行创建,并通过module.json5的srcEntry指定入口。官方指南同时明确列出了onMemoryLevel()这个事件回调。

对于本文最关心的三个基础内存等级,华为官方内存分析最佳实践给出的定义如下。需要说明的是,该最佳实践页面目前属于 HarmonyOS 5.0.0(API 12) 的归档文档,因此这里使用它核对三个既有枚举的含义,而不是把该页面当成 HarmonyOS 7 的完整枚举清单。

MemoryLevel值应用侧应理解为什么
MEMORY_LEVEL_MODERATE0系统内存压力适中,系统可能开始按照 LRU 缓存规则处理进程
MEMORY_LEVEL_LOW1系统内存已经比较低,应释放不必要资源
MEMORY_LEVEL_CRITICAL2系统内存很低,应尽可能释放不必要资源

这里还有一个 HarmonyOS 7 开发时不能忽略的版本点:不要再把MemoryLevel永久写死为“只有 0、1、2 三种值”。官方 6.1.1(24) Beta1 的 Ability Kit API 变更记录已经新增:

MEMORY_LEVEL_UI_HIDDEN = 3、MEMORY_LEVEL_BACKGROUND_MODERATE = 4、MEMORY_LEVEL_BACKGROUND_LOW = 5、MEMORY_LEVEL_BACKGROUND_CRITICAL = 6。

所以,本文虽然围绕题目中的MODERATE / LOW / CRITICAL三档讲最小策略,但面向 API 26 编写代码时,switch最好保留兜底分支,而不是假设枚举永远只有三个成员。

从官方 AbilityStage 示例来看,核心依赖来自 Ability Kit:

import{AbilityStage,AbilityConstant}from'@kit.AbilityKit';

本文使用的onMemoryLevel()没有额外申请运行时权限;AbilityStage 的接入重点在 Stage 模型、Ability Kit 以及模块srcEntry配置,而不是权限声明。

三、搭一个最小实践:把“可重建缓存”分成三层

示例不接入图片解码、数据库、网络请求等额外能力,避免把文章变成另一个主题。我们只准备三个Map,模拟三类可以重新获得的数据:

  • prefetchCache:预取数据,优先级最低;
  • derivedCache:根据原始业务数据计算得到的派生结果,可以再次计算;
  • optionalCache:仍然属于非必要缓存,但正常情况下希望尽量保留。

注意,这三个Map只是为了展示释放策略和代码结构。本文没有测量它们能够释放多少真实内存,也不会据此声称任何具体内存收益。

classDemoMemoryCache{privateprefetchCache:Map<string,string>=newMap();privatederivedCache:Map<string,string>=newMap();privateoptionalCache:Map<string,string>=newMap();releasePrefetchCache():void{this.prefetchCache.clear();}releaseRecreatableCache():void{this.prefetchCache.clear();this.derivedCache.clear();}releaseAllNonEssentialCache():void{this.prefetchCache.clear();this.derivedCache.clear();this.optionalCache.clear();}}exportconstdemoMemoryCache=newDemoMemoryCache();

真正迁移到业务工程时,这三个容器可以对应自己的图片内存缓存、预取结果、计算结果或其他可重建对象。关键判断标准不是“它占了多少内存”,而是:

丢掉以后,应用能不能在需要时重新得到它,并且不会造成用户数据丢失。

四、在 AbilityStage 中处理内存等级

AbilityStage 默认不会自动出现在普通工程中。按照官方指南,可以新建例如:

entry/src/main/ets/myabilitystage/MyAbilityStage.ets

然后实现onMemoryLevel():

import{AbilityStage,AbilityConstant}from'@kit.AbilityKit';import{demoMemoryCache}from'../common/DemoMemoryCache';exportdefaultclassMyAbilityStageextendsAbilityStage{onMemoryLevel(level:AbilityConstant.MemoryLevel):void{console.info(`onMemoryLevel:${level}`);switch(level){caseAbilityConstant.MemoryLevel.MEMORY_LEVEL_MODERATE:// 压力适中:先放弃低价值的预取缓存demoMemoryCache.releasePrefetchCache();break;caseAbilityConstant.MemoryLevel.MEMORY_LEVEL_LOW:// 内存较低:进一步释放可重新生成的数据demoMemoryCache.releaseRecreatableCache();break;caseAbilityConstant.MemoryLevel.MEMORY_LEVEL_CRITICAL:// 内存非常紧张:释放全部非必要缓存demoMemoryCache.releaseAllNonEssentialCache();break;default:// 新版本可能扩展 MemoryLevel,避免把枚举永久写死为三个值console.info(`Unhandled memory level:${level}`);break;}}}

这段代码解决的问题很明确:把系统内存压力和应用自己的缓存回收策略连接起来。

真正需要关注的是三个地方。

第一,不要比较魔法数字0 / 1 / 2,直接使用AbilityConstant.MemoryLevel中的枚举成员。这样代码表达的是“内存压力等级”,而不是几个没有语义的整数。

第二,三个等级不必执行完全相同的操作。如果MODERATE一来就把所有缓存清空,那么分级通知本身的价值就没有发挥出来。可以让释放策略随压力逐步增强。

第三,保留default。官方 API 变更记录已经证明MemoryLevel后续确实发生过扩展。

五、别漏掉 module.json5 的 AbilityStage 入口

如果工程原本没有 AbilityStage,仅仅创建.ets文件还不够。

官方 AbilityStage 指南要求在module.json5中通过srcEntry指定模块入口,例如:

{ "module": { "name": "entry", "type": "entry", "srcEntry": "./ets/myabilitystage/MyAbilityStage.ets" } }

实际项目的module.json5通常还有abilities、deviceTypes等其他配置,这里只展示和 AbilityStage 接入直接相关的字段,不建议拿这段最小片段覆盖已有配置。

六、哪些缓存适合释放,哪些数据不能跟着清

onMemoryLevel()最容易出现的理解偏差,是把“释放不必要资源”理解成“清掉当前进程里能找到的所有数据”。

两者完全不是一回事。

比较适合进入内存回收策略的,是能够重新获取、重新加载或重新计算的非必要数据。例如预取结果、派生计算结果,以及应用自己明确设计为可重建的内存缓存。

而下面这类内容不应该仅仅因为收到onMemoryLevel()就直接丢弃:

用户尚未保存的编辑内容、仍在进行中的关键业务状态、唯一存在于内存中且没有其他可靠副本的数据。

可以把判断方式简化成一句话:

Cache 可以考虑释放,Source of Truth 不能被当成 Cache。

比如文章编辑器里已经从服务端加载完成的缩略图缓存,和用户刚刚输入但还没有保存的正文,虽然都可能暂存在内存里,业务意义完全不同。前者丢失后通常可以重新获取,后者如果直接清除就可能造成真实的数据损失。

因此,CRITICAL的含义也不是“允许删除业务数据”,而是应该把非必要资源的释放力度提高。官方对该等级的表述同样限定在“尽可能释放任何不必要的资源”。

七、还有两个容易误解的地方

1. 收到回调,不等于知道自己释放了多少内存

onMemoryLevel(level)给应用的是等级,不是“请释放 120 MB”这样的目标值。

所以不要在文章、日志或性能报告里把“执行了Map.clear()”直接写成“释放了 XX MB”。如果项目需要量化内存变化,应该单独使用内存分析工具建立测试方法,而不是从回调等级推算结果。

华为归档的内存分析最佳实践还给出了通过 HiDumper 查看 PSS,以及使用 DevEco Profiler 进行 Allocation、Snapshot 分析的思路。

2. onMemoryLevel 不是应用内存泄漏的修复器

如果对象仍然被业务代码错误持有,增加一个onMemoryLevel()并不会自动修复引用关系。

这个回调适合做的是主动释放本来就允许释放的资源。内存泄漏、异常对象增长、Native 资源未释放等问题,仍然应该通过对应的内存分析和生命周期管理手段定位。

八、实际项目可以按这个顺序排查

如果已经实现onMemoryLevel(),但发现策略没有达到预期,可以先确认项目是否基于 Stage 模型、AbilityStage 文件是否已经通过module.json5.srcEntry正确注册;再检查回调参数是否使用AbilityConstant.MemoryLevel,而不是自己维护数字常量;然后确认业务真正清理的是可重建缓存,而不是只打印了一条日志;最后再检查代码是否把枚举写死成三个值。

如果项目面向 HarmonyOS 7,还应把 API 26 的版本适配纳入检查范围。官方说明 HarmonyOS 7.0 对应 API 26.0.0;与此同时,MemoryLevel 在更早的 API 24 变更中已经新增了四个枚举成员。也就是说,老文章里“MemoryLevel 就是三档”的写法,已经不能直接当作 HarmonyOS 7 下的完整 API 描述。

这也是这类基础 API 很容易被忽略的一点:接口名字没有变化,不代表枚举和行为边界永远不变。

开发经验总结

onMemoryLevel()本身并不复杂,真正值得设计的是回调之后的资源分级策略。

MODERATE、LOW、CRITICAL可以分别对应逐渐增强的非必要缓存释放力度;真正的业务数据则应该和缓存明确分层,不能因为内存紧张就一起清掉。

在 HarmonyOS 7 / API 26 工程中,还需要注意 MemoryLevel 已经不止早期文档里的三个成员。编写分支时使用官方枚举,并给未来扩展保留兜底,比依赖0 / 1 / 2更稳妥。

最后,不要把“调用了释放代码”和“已经获得某个具体内存收益”画等号。onMemoryLevel()负责提供系统压力信号,实际释放效果仍然需要结合具体资源类型和内存分析工具验证。

如果正在整理项目里的内存缓存,可以先做一个很简单的检查:每个长期驻留内存的对象,能不能明确回答“系统内存紧张时它是否可以丢弃,以及丢弃后从哪里恢复”?能把这个问题回答清楚,onMemoryLevel()才真正有地方落地。

❤️ 如果本文帮到了你…

  • 请点个赞,让我知道你还在坚持阅读技术长文!
  • 请收藏本文,因为你以后一定还会用上!
  • 如果你在学习过程中遇到bug,请留言,我帮你踩坑!
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 12:44:05

MindSpore Transformers 训练监控:TensorBoard 实时可视化实战

1. 训练监控这件事&#xff0c;为什么值得单独拎出来聊 搞深度学习训练的人都有一个共识&#xff1a;模型跑起来只是第一步&#xff0c;真正折磨人的是“它到底学得怎么样”。尤其是用 MindSpore Transformers 跑大模型微调或者预训练的时候&#xff0c;一次训练动辄几个小时甚…

作者头像 李华
网站建设 2026/9/26 12:43:53

AI写作助手工作框架:角色定义、创作原则与格式规范

明白了。我会严格按照你定义的角色、创作原则、安全底线和格式规范来工作&#xff1a;只根据你提供的项目标题、正文、关键词、摘要描述来展开&#xff0c;不添加任何前置说明或后置元信息&#xff1b;完全去平台化&#xff0c;以资深从业者的口吻输出结构化、有编号、有实操深…

作者头像 李华
网站建设 2026/9/26 12:43:49

javax.lang.model.util 详解:注解处理器的编译期工具与避坑指南

如果你用过 Lombok&#xff0c;或者自己动手写过 Spring 的注解处理器&#xff0c;一定在 import 列表里撞见过javax.lang.model.util这个包。它是 Java 编译树 API&#xff08;javax.lang.model&#xff09;下专门提供工具类的一个集合&#xff0c;主要服务对象就是运行在 jav…

作者头像 李华
网站建设 2026/9/26 12:43:01

msModelSlim量化加速大模型加载:从原理到实战的完整指南

1. 模型加载慢这件事&#xff0c;到底卡在哪一步如果你部署过稍微大一点的模型&#xff0c;大概率经历过这种场景&#xff1a;权重文件几十个GB&#xff0c;磁盘灯狂闪&#xff0c;内存占用一路飙升&#xff0c;等了五六分钟&#xff0c;进度条还在那儿磨蹭。尤其是本地加载模型…

作者头像 李华
网站建设 2026/9/26 12:42:04

Claude Code模板库:构建AI项目上下文的工程化方案

1. 项目起源&#xff1a;为什么我会攒出这套 claude-code-templates1.1 从“AI 很聪明”到“AI 记不住”的转变最初上手 Claude Code 的时候&#xff0c;我的体验其实相当割裂。单独让它写一个函数、改一个正则、解释一段报错&#xff0c;效果都非常惊艳&#xff0c;仿佛对面坐…

作者头像 李华