高级应用程序中的内存使用
本主题提供有关高级应用程序中的内存使用的详细信息。 有关可用于实时应用程序 (RTApps) 的内存的信息,请参阅 管理内存和延迟注意事项 。
高级应用程序有权访问以下内存和存储:
- 高级核心上的 256 KiB RAM,完全保留供高级应用程序使用。 最多可以为高级应用程序和 RTApp 通信的每个共享缓冲区通道分配最多 1 KiB 的空间。
- 1 MiB 只读闪存,在高级核心和实时核心之间共享。
- 可读/写 (可变) 存储,在设备重新启动时会保留该存储。 有关可变存储的信息,请参阅 在 Azure Sphere 上使用存储。
注意
反复更新闪光灯最终会将其磨损并使其无效。 因此,应设计代码以避免不必要的闪存更新。 例如,如果要在退出之前保存应用程序状态,以便可以在重启后恢复保存的状态,请考虑仅在状态已更改的情况下将应用程序的状态保存到闪存。
确定闪存内存使用情况
若要确定闪存使用情况,请仅考虑映像包文件的大小,其中包括映像元数据、应用程序清单和可执行映像。 无需考虑 Microsoft 提供的组件(例如 Azure Sphere OS 或运行时服务和共享库)所需的存储,这些组件控制外围设备并启用与Azure IoT 中心的连接。 同样,无需包含应用程序的完整备份副本的大小,也不需要包含在出现损坏或无线更新问题时启用故障转移或回滚的组件的大小。
但是,在开发和调试期间,调试器的大小会计入限制。 调试器由 azsphere device enable-development 自动添加,并由 azsphere device enable-cloud-test 删除。 可以通过在 Microsoft Azure Sphere SDK 安装目录的 DebugTools 文件夹中搜索 gdbserver.imagepackage 来查找 SDK 使用的调试器的大小。
如果应用程序映像包和调试器 ((如果存在) 超过 1 MiB 的总限制, 则 azsphere device sideload 命令将返回错误。 将新映像上传到 Azure Sphere 租户的 azsphere image add --image 命令还会在映像包超过 1 MiB 时返回错误。
256 KiB RAM 限制仅适用于应用程序;无需允许调试器使用的 RAM。 额外的内存是为内核分配保留的。
可用的闪存和 RAM 可能会增加 (但永远不会减少为当前 Azure Sphere 芯片 (MT3620) 编写的应用程序的) 。 未来的 Azure Sphere 芯片可能有不同的限制。
内存不足情况
如果应用程序使用过多的 RAM,Azure Sphere OS 会用 SIGKILL 信号终止它。 例如,在调试器中,你将看到以下内容:
Child terminated with signal = 0x9 (SIGKILL)
如果高级应用程序在收到 SIGTERM 请求后无法退出,也会发生 SIGKILL 信号。 有关详细信息 ,请参阅应用程序的生命周期 。
若要帮助避免应用程序因内存不足而崩溃,请参阅 管理高级应用程序中的 RAM 使用情况的最佳做法。
确定运行时应用程序 RAM 使用情况
Azure Sphere 提供了多个函数,用于在运行时获取内存使用情况信息。 可以使用这些来监视高级应用程序的内存使用情况,以便在内存使用量超过在 256 KiB 限制中指定的阈值时安全地重启应用程序。 可用的函数包括:
- Applications_GetTotalMemoryUsageInKB:获取总内存使用量(以千字节为单位)。 这是系统上应用的总物理内存使用量,包括内核分配 (例如代表应用或调试服务器的套接字) 缓冲区,在 KiB) 中作为原始值 (返回。
- Applications_GetUserModeMemoryUsageInKB:获取用户模式内存使用情况(以千字节为单位)。 这是应用直接使用的物理内存量、代表其 (的任何库使用的内存量(也称为 anon 分配) )和调试服务器使用的内存(在 KiB) 中作为原始值 (返回)。
- Applications_GetPeakUserModeMemoryUsageInKB:获取峰值用户模式内存使用量(以千字节为单位)。 这是当前会话中使用的最大用户内存量。 测试应用程序的内存使用情况时,应确保此值永远不会超过 256 KiB。 每当应用重启或重新部署时,此值将重置。 使用此函数大致了解应用程序接近 256 KiB 建议的限制。
若要在高级应用程序中使用这些函数,请包含 applications.h 头文件。 可以在开发期间使用这些函数来了解应用程序的总体内存使用情况,但还可以将它们与日志记录一起使用 ,以从现场的设备捕获信息。 内存过度使用检测和清理代码片段演示如何检测和正常处理意外内存使用情况。
注意
这些函数返回 OS 看到的内存使用情况。 目前,这些函数不会报告应用程序释放内存以对用户堆进行分配的情况。 内存将返回到 malloc 库以供将来使用,但 OS 报告的统计信息保持不变,除非操作系统本身分配并释放了内存。 例如,为套接字分配内存。 因此,这些函数有助于了解最坏的情况,以帮助应用程序保守地运行以获得最大可靠性。 值是近似值,可能因 OS 版本而异。
添加堆内存分配跟踪
可以通过添加 堆内存分配跟踪来获取其他内存使用情况信息,该跟踪显示静态和动态链接库正在执行哪些用户和内核分配。 这样可以更全面地了解应用程序在何处使用内存,以帮助你最有效地使用它。 此功能在 Azure Sphere OS 版本 21.07 或更高版本和应用程序运行时版本 (ARV) 10 或更高版本中可用,仅适用于支持开发的设备,并且仅在应用程序 未 在调试器下运行时使用。
注意
必须完成本部分所述的两个配置任务,堆内存分配跟踪才能正常工作。 如果未能执行此操作,编译期间将报告警告,并且不会显示堆内存信息。
若要启用堆内存分配跟踪,需要执行两项操作:
将 HeapMemStats 功能添加到应用程序的 app-manifest.json 文件:
"Capabilities": { "HeapMemStats": true },
通过将 libmalloc 库添加到应用程序的 CMakeLists.txt 文件中的 命令,将 libmalloc 库添加到
DEBUG_LIB "libmalloc"
azsphere_target_add_image
映像包:azsphere_target_add_image_package(${PROJECT_NAME} DEBUG_LIB "libmalloc")
重要
由于堆内存分配跟踪仅适用于支持开发的设备,因此,在生成用于部署的映像包之前,应执行以下操作以将其从应用程序中删除:
- 从应用程序的 app-manifest.json 文件中删除行“HeapMemStats:true”。
- 从
azsphere_target_add_image_package(${PROJECT_NAME} DEBUG_LIB "libmalloc"
应用程序的 CMakeLists.txt 文件中的 命令中删除DEBUG_LIB "libmalloc"
。
使用 Visual Studio 性能探查器
如果使用 Visual Studio,可以使用其性能探查器功能来获取有关应用程序内存使用情况的信息。 有关使用此探查器的教程,请参阅 Tutorials/MemoryUsage。
先决条件
- Azure Sphere 开发工具包连接到运行 Visual Studio 且已安装 Azure Sphere SDK 的电脑。 请参阅 安装适用于 Windows 的 Azure Sphere SDK。
- 为开发准备的设备。 请参阅 azsphere device enable-development。 如果未为设备启用开发,则性能探查器不会返回数据。
启动内存使用情况探查器
选择“ 调试>性能探查器 ”或按 Alt+F2 打开性能探查器启动窗口。
在 “分析目标”下,如果 “Azure Sphere 设备探查器 ”不可见,请选择“ 选择目标 ”,然后选择“ Azure Sphere 设备探查器”。
在 “可用工具”下,确保选中 “Azure Sphere 内存使用情况 ”,然后选择“ 启动 ”以打开内存使用情况分析窗口并启动内存探查器。
如果需要部署或重启应用程序,请选择“ 调试>启动但不调试” 或按 Ctrl+F5 将应用程序部署到设备。
重要
若要获取应用程序的准确 RAM 使用情况信息,请务必[在不调试 的情况下 启动应用] (buid-hl-app.md#build-and-deploy-the-application-in-visual-studio-without-debugging) 。 在调试器下运行应用将导致 RAM 使用率过高,因为调试服务器消耗的内存将包含在报告的 RAM 使用情况统计信息中。
解释内存使用情况探查器数据
内存使用情况分析窗口显示如下所示的视图:
在视图的中心, Azure Sphere 设备物理内存 图绘制了三个不同的 RAM 使用情况统计信息, (在应用运行时以三个不同的行的形式显示到最近的 KiB) :
- 总: 系统上应用的总物理内存使用量,包括内核分配 (,例如代表应用或调试服务器) 套接字的缓冲区。
- 用户: 应用直接使用的物理内存量、任何库代表其使用的内存 (也称为 anon 分配) ,以及调试服务器使用的内存。
- 峰值用户: 当前会话中使用的最大用户内存量。 测试应用程序的内存使用情况时,应确保此值永远不会超过 256 KiB。 额外的内存是为内核分配保留的。 每当应用重启或重新部署时,此值将重置。
该图还绘制由三角形) 表示的新高峰事件 (。 每当有新的峰值用户内存使用量最大值时,将发生此事件。 为屏幕阅读器辅助功能启用事件。
如果已启用 堆内存分配跟踪 ,并且应用程序未在调试器下运行,你将看到一个显示堆内存统计信息的附加图:
- 总堆数:应用程序或代表应用程序分配的总堆内存,包括静态和动态库。
- 共享库堆:Azure Sphere OS 提供的动态链接库的分配。
在图形上方,时间线视图显示应用的运行时间,与下图中的数据相关。 使用 “放大 ”和“ 缩小” 功能关注特定时间段。
在图形下方,表视图显示相同的内存统计信息和事件。
提示
若要将数据从表复制到剪贴板,请按 Ctrl+A 选择所有行,然后按 Ctrl+C。
本部分所示的前两个图形是在运行 内存使用情况教程的第 1 阶段时拍摄的,其中包含内存泄漏。 内存使用量在每个图形中单调攀升,为泄漏提供视觉证据。 修复泄漏时,如 内存使用情况教程的第 2 阶段所示,随着内存的分配和解除分配,图形会上升和下降。
查看有关总内存使用量的统计信息
azsphere device app show-memory-stats 命令返回附加设备上运行的应用程序的总内存使用量、用户模式使用情况和峰值用户模式使用情况的内存使用情况统计信息。 设备必须配置 appDevelopment 设备功能才能运行此命令。
应用运行时显示的 RAM 使用情况统计信息如下:
- 总 (内核 + 用户模式) :系统上应用的总物理内存使用量,包括内核分配 (,例如代表应用或调试服务器) 套接字的缓冲区。
- 用户模式:应用直接使用的物理内存量、代表其 (的任何库使用的内存量(也称为 anon 分配) ),以及调试服务器使用的内存。
- 峰值用户模式:当前会话中使用的最大用户内存量。 测试应用程序的内存使用情况时,应确保此值永远不会超过 256 KiB。 额外的内存是为内核分配保留的。 每当应用重启或重新部署时,此值将重置。
如果已启用 堆内存分配跟踪 ,并且应用程序未在调试器下运行,则会看到其他堆内存统计信息行:
- 堆:应用 + 静态库:代码中的内核和用户分配,以及静态链接到它的任何库。
- 堆: <动态库分配>:Azure Sphere OS 提供的单个动态链接库的分配。
持续监视内存使用情况
若要监视一段时间内的内存使用情况,可以使用脚本在循环中运行 azsphere device app show-memory-stats 命令,如以下示例中所述:
Windows 命令提示符
使用记事本或其他文本编辑器创建包含以下内容的批处理脚本文件 memuse.bat:
@echo off
:loop
call azsphere device app show-memory-stats
choice /d y /t 1 > nul
goto loop
如果在命令提示符处键入批处理脚本的名称, (或文件的完整路径(如果它不在当前目录中,) )来运行该脚本:
C:\Users\username> memuse.bat
-------------------------- -------------
Name Usage (bytes)
========================================
Total (Kernel + User Mode) 65536
-------------------------- -------------
User Mode 36864
-------------------------- -------------
Peak User Mode 36864
-------------------------- -------------
-------------------------- -------------
Name Usage (bytes)
========================================
Total (Kernel + User Mode) 65536
-------------------------- -------------
User Mode 36864
-------------------------- -------------
Peak User Mode 36864
-------------------------- -------------
若要退出脚本,请在命令提示符窗口中键入 Ctrl+C,然后对“终止批处理作业?”提示符回答 Y。
Windows PowerShell
while ($true) {
azsphere device app show-memory-stats
Start-Sleep -Seconds 1
}
内存使用情况和调试器
在调试器下运行应用时,报告的内存统计信息还包括调试服务器进程的内存使用情况以及由调试引起的其他内存使用情况,例如设置断点。 因此,在尝试收集准确的内存统计信息时,应始终运行应用而不进行调试。
但是,如果使用调试器运行应用,则使用内存使用情况探查器可能很有用。 在观察内存消耗的相对变化时设置断点和单步执行代码行,对于确定内存使用量高峰或内存泄漏的原因,可能是一种有用的技术。
在 Visual Studio 中调试时,性能探查器会自动打开,但不显示堆内存分配跟踪。