异常场景
在使用软件进行多路视频流渲染时明显出现软件卡顿闪退现象,启动后监控系统管理器内存,CUP占用飙升,两者占用率达 90% 以上后将出现无响应闪退情况,疑似触发 OOM;
期间通过自定义命令打印内存使用
while ($true) {
$memInfo = Get-WmiObject -Class Win32_OperatingSystem
$availableMemory = [math]::round($memInfo.FreePhysicalMemory / 1024, 2)
$totalMemory = [math]::round($memInfo.TotalVisibleMemorySize / 1024, 2)
$usedMemory = [math]::round(($totalMemory - $availableMemory), 2)
Write-Output "Total Memory: $totalMemory MB"
Write-Output "Used Memory: $usedMemory MB"
Write-Output "Available Memory: $availableMemory MB"
Write-Output "----------"
Start-Sleep -Seconds 5
}
内存回收记录
Total Memory: 16059.28 MB
Used Memory: 15740.98 MB
Available Memory: 318.3 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15158.36 MB
Available Memory: 900.92 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15445.71 MB
Available Memory: 613.57 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15735.45 MB
Available Memory: 323.83 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15578.71 MB
Available Memory: 480.57 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15788.57 MB
Available Memory: 270.71 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15461.94 MB
Available Memory: 597.34 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15679.18 MB
Available Memory: 380.1 MB
----------
Total Memory: 16059.28 MB
Used Memory: 16037.23 MB
Available Memory: 22.05 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15614.89 MB
Available Memory: 444.39 MB
----------
Total Memory: 16059.28 MB
Used Memory: 14949.76 MB
Available Memory: 1109.52 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15263.12 MB
Available Memory: 796.16 MB
----------
Total Memory: 16059.28 MB
Used Memory: 15735.75 MB
Available Memory: 323.53 MB
----------
Total Memory: 16059.28 MB
Used Memory: 14907.19 MB
Available Memory: 1152.09 MB
----------
日志分析
内存使用量有波动,显示出系统正在积极管理内存资源以避免 OOM。
从数据中可以观察到 Used Memory 和 Available Memory 之间的显著波动。这些波动可以是多种系统行为的结果,尤其是在系统尝试管理内存资源避免 OOM(Out of Memory)错误时。应该要经历以下几个阶段
1. 内存回收
当系统内存使用率过高时,操作系统会触发内存回收机制来释放不再需要的内存资源。这可能会导致 Available Memory 突然增加,而 Used Memory 突然减少。这是通过释放不再使用的内存块、清理缓存、交换文件等操作实现的。
2. 申请虚拟内存
Windows 系统在物理内存不足时,会使用虚拟内存(Page File)。当系统需要更多内存而物理内存不足时,部分内存内容会被交换到磁盘上的虚拟内存中,从而释放物理内存。这会导致 Available Memory 突然增加,尽管 Used Memory 可能没有显著变化。
3. 应用程序崩溃或终止
如果某个应用程序使用了大量内存并且达到了系统能承受的极限,操作系统可能会强制终止该应用程序以释放内存资源。这会导致 Used Memory 突然减少,Available Memory 突然增加。
4. 内存泄漏检测和处理
系统或某些应用程序可能会检测到内存泄漏,并尝试回收这些泄漏的内存。这会导致 Available Memory 突然增加,而 Used Memory 突然减少。
结论
内存波动显示系统正在积极通过回收不必要的内存、使用虚拟内存等方式来避免 OOM 错误。如果这些操作不能满足需求,应用可能会经历以下周期:
- 内存使用量逐渐增加。
- 系统尝试回收内存。
- 内存仍然不足时,应用卡顿。
- 最终系统可能会强制终止某些应用来释放内存,导致闪退。
OOM 问题
OOM 除了引发应用闪退,还可能引发系统无响应、性能显著下降等问题。这些都与操作系统的内存管理和垃圾回收机制密切相关。
1. 应用程序卡顿
对于一些编程语言和运行时环境(如 .NET 和 Java),垃圾回收是内存管理的一部分。垃圾回收器定期检查和回收不再使用的内存。这会导致:
- 暂停应用程序:垃圾回收器运行时,会暂停所有应用程序线程,以便安全地回收内存。
- 高 CPU 占用:垃圾回收过程需要计算和遍历内存,可能会导致 CPU 使用率上升。
2. 系统卡顿
当系统资源紧张时,各个进程会争夺有限的 CPU、内存和 I/O 资源。这会导致:
- 系统响应变慢:各个进程需要等待资源变得可用。
- 高上下文切换:频繁的进程切换会增加 CPU 开销,从而进一步降低系统性能。
页内存管理
Windows系统通过虚拟内存、页面置换和内存回收等机制管理内存。在发生OOM之前,系统会经历一系列优化步骤,如内存警告、页面置换、内存回收和进程终止等。
-
页缓存和预取:
- 系统会缓存最近访问的页面,并预取一些可能会被访问的页面,以提高性能。
-
页面置换(Page Replacement) :
- 当物理内存不足时,系统会选择一些页面移到页面文件中,腾出物理内存。这些页面可能是最近不常访问的页面。
- 常见的页面置换算法包括LRU(Least Recently Used)、FIFO(First In First Out)等。
-
内存回收:
- 系统会定期回收未使用的内存,如未引用的对象或释放的内存块。
OOM 的一些解决方案
增加物理内存
原因:当系统物理内存不足时,操作系统会频繁使用页面交换,将内存中的数据写入硬盘上的页面文件。这会导致系统性能显著下降,因为硬盘读写速度远慢于内存访问速度。 解决方案:
通过增加物理内存(RAM)容量,可以显著提升系统的整体性能,减少页面交换的频率。 评估需求:根据应用程序和工作负载的需求,合理规划和配置内存容量。例如,运行大型数据库或虚拟机时,需要更高的内存容量。
使用SSD
原因:相较于传统的HDD,SSD有更快的读写速度,可以显著减少页面交换带来的性能损失。
替换硬盘:将系统硬盘从HDD升级为SSD,可以大幅提升系统启动速度和应用程序加载速度。 混合存储方案:在预算有限的情况下,可以采用SSD和HDD的混合存储方案,将操作系统和常用应用程序安装在SSD上,将大文件和不常用数据存储在HDD上。 优化SSD使用:定期进行SSD维护,如固件更新、TRIM命令执行,确保SSD性能稳定。
系统层面优化
操作系统层次
原因:不必要的应用程序和后台进程会占用大量内存资源,导致系统整体内存压力增大。
- 关闭不必要的应用程序:
- 定期检查和关闭不再使用的应用程序,释放被占用的内存资源。
- 优化启动项,通过系统配置工具(如Windows的Task Manager)管理和优化开机启动项;
应用层面优化
应用层(尤其是使用托管语言如Java、.NET的应用程序)
原因:垃圾回收机制是某些编程语言内存管理的一部分,频繁的垃圾回收会导致应用程序暂停和CPU使用率上升,从而影响系统性能。
编程方面:
- 选择合适的数据结构:使用适合需求的数据结构,避免内存浪费。
- 减少对象创建:尽量重用对象,避免频繁创建和销毁对象。
- 内存泄漏检测:使用工具检测和修复内存泄漏问题。
- 代码优化:优化算法,减少不必要的计算和内存分配。
垃圾回收优化
- 调整垃圾回收参数:根据应用特点调整垃圾回收参数和策略。
- 内存管理优化:通过优化代码和内存管理,减少不必要的对象创建和销毁,降低垃圾回收的频率。
- 使用合适的垃圾回收器:选择适合应用负载的垃圾回收器,如G1、ZGC(Java)等。
- 监控和调试:定期监控垃圾回收行为,及时调整策略。
优化对比
以投入成本对比输出
| 优化方式 | 实现难度 | 人工成本 | 作用 | 优先级 |
|---|---|---|---|---|
| 关闭不必要的应用程序 | 低 | 低 | 中等 | 1 |
| 优化启动项 | 低 | 低 | 中等 | 2 |
| 监控和调试垃圾回收行为 | 中 | 高 | 高 | 3 |
| 减少对象创建 | 中 | 中 | 高 | 4 |
| 选择合适的数据结构 | 中 | 中 | 高 | 5 |
| 使用合适的垃圾回收器 | 高 | 高 | 高 | 6 |
| 内存泄漏检测 | 高 | 高 | 高 | 7 |
| 代码优化 | 高 | 高 | 高 | 8 |
综合:
内存优化方案及其优先级排序
-
关闭不必要的应用程序和优化启动项 作为最容易实现且成本最低的方法,可以优先实施。定期检查并关闭不再使用的应用程序,使用系统配置工具管理和优化开机启动项,能迅速释放内存资源,提高系统响应速度。
-
使用合适的垃圾回收器和监控调试垃圾回收行为 根据应用需求选择合适的垃圾回收器(如 Java 中的 G1、ZGC),并使用监控工具(如 VisualVM、JConsole)监控垃圾回收行为,调整垃圾回收参数。虽然成本高,但能迅速优化内存管理效果显著,提高系统稳定性,适合有技术背景的团队。
-
内存泄漏检测和代码优化 使用内存泄漏检测工具(如 Valgrind、LeakCanary、VisualVM)识别并修复内存泄漏问题,选择合适的数据结构,减少对象创建,优化算法,降低内存和 CPU 的消耗。尽管成本高且耗时多,但对应用性能提升作用最大,适合有长期优化计划的项目。
-
局部重构 在编程层面进行代码重构,优化数据结构和算法,减少内存和 CPU 的消耗。虽然成本高且耗时长,但能显著提升应用性能,解决深层次的性能问题,适合需要进行深度性能优化的项目。