一、MemoryManagerImpl(整个应用的内存"中枢神经系统")
它负责全面监控、协调和管理应用的内存使用情况,其核心目标是确保在内存资源有限的移动设备上,相机这一高资源消耗型应用能够稳定、流畅地运行,避免因内存不足(Out of Memory)而导致的崩溃、性能下降或功能中断,从而保障最终用户的拍摄体验。
1.响应系统级内存事件
该类通过实现 ComponentCallbacks2接口,具备了直接响应系统级内存事件的能力。当 Android 系统整体内存紧张时,会向应用发送 onTrimMemory(int level)回调。该类内部定义了一个关键状态数组 sCriticalStates,用于过滤出需要立即采取行动的严重内存压力信号(如 TRIM_MEMORY_RUNNING_CRITICAL)。一旦接收到这些信号,它便会主动通知所有监听者,触发应用内部的内存释放流程。同时,它还实现了 onLowMemory()方法,作为最后一道防线来应对极端的内存不足情况。
| 特性 | onTrimMemory(int level) |
onLowMemory() |
|---|---|---|
| 精确度 | 精细分级 。系统会传入一个 level参数(如 TRIM_MEMORY_RUNNING_MODERATE),指明内存紧张的严重程度和应用的状态(前台、后台等)。 |
粗放紧急。没有分级,只有一个终极警告。 |
| 严重程度 | 从"提醒"到"严重"不等。应用可以根据级别采取不同力度的释放策略。 | 最高级别。是系统在"万不得已"时发出的最后通牒。 |
| 处理逻辑 | 在 MemoryManagerImpl中,它只过滤处理最严重的几个状态(如 TRIM_MEMORY_RUNNING_CRITICAL),然后才触发 notifyLowMemory()。 |
只要被调用,就无条件 地触发 notifyLowMemory()。 |
java
@Override
public void onTrimMemory(int level) {
for (int i = 0; i < sCriticalStates.length; ++i) {
if (level == sCriticalStates[i]) {
notifyLowMemory();
return;
}
}
}
java
@Override
public void onLowMemory() {
notifyLowMemory();
}
private void notifyLowMemory() {
synchronized (mListeners) {
for (MemoryListener listener : mListeners) {
listener.onLowMemory();
}
}
}
2.监控应用内部的核心内存消耗源
除了响应系统事件,该类还通过实现 MediaSaver.QueueListener接口,监控应用内部的核心内存消耗源------媒体文件(照片、视频)的保存队列。当媒体保存队列已满(onQueueStatus(true)),意味着待处理的数据积压过多,内存消耗可能即将达到临界点,此时管理器会提前发出警告,通知相关组件暂停或减缓可能进一步消耗内存的操作(如连续拍摄),这是一种主动的、应用层的内部分级预警机制。
为了有效地分发这些内存状态信息,该类采用了观察者设计模式。它维护了一个监听器列表 (mListeners),允许应用中的其他组件(如相机控制器、图像处理模块等)注册为监听者。当内存状态发生变化时,无论是系统通知还是队列告警,它都会同步地遍历所有监听器并调用相应的回调方法(如 onLowMemory()或 onMemoryStateChanged),确保所有相关部分都能协同响应,实现统一的内存管理策略。
在内存分配策略上,该类的一个重要职责是计算并限制本地(Native)代码可以使用的最大内存量。它通过一个辅助方法 getMaxAllowedNativeMemory来实现此功能。该方法首先检查系统配置(Gservices)中是否存在预设的覆盖值,为调试和适配不同设备提供了灵活性。如果没有配置,则采用默认计算策略:获取应用可用的最大 Dalvik 堆内存(取常规 MemoryClass和大型 LargeMemoryClass中的最大值),并取其 70% (MAX_MEM_ALLOWED) 作为 Native 内存的上限。这 30% 的缓冲空间是为处理高分辨率照片、连拍或视频录制等特别耗内存的操作预留的,防止 Native 层耗尽所有内存而导致 Java 层崩溃。
最后,该类通过一个静态的 create(...)工厂方法对外提供实例化服务。这个方法确保了对象被正确且完整地"装配":它不仅创建了 MemoryManagerImpl 实例本身,还自动将其注册为系统的组件回调接收者,并将其设置为 MediaSaver 的队列监听器。这种设计将复杂的依赖设置和注册逻辑封装在内部,简化了外部的调用过程,保证了管理器在创建后立即处于完全工作状态。
二、MemoryQuery和MemoryManager
这两个Java类共同构成了Android相机应用中内存管理系统的两个关键层面,体现了清晰的职责分离和协作关系。
MemoryQuery类作为一个具体的数据查询工具,其核心作用是深入系统底层,通过ActivityManager和Debug.MemoryInfo等Android API来采集详细的内存使用数据。它能够获取包括可用内存、总内存、进程内存使用情况(PSS)、各组件内存分配以及系统内存阈值等一系列关键指标,并将这些数据转换为统一的键值对格式,为上层决策提供准确的数据支持。
另一方面,MemoryManager接口则扮演了管理协调者的角色,它并不直接处理数据采集,而是定义了一套内存管理的框架和规范。它通过监听器模式(MemoryListener)允许应用中的其他模块(如相机模块、图像处理模块)注册成为内存状态变化的观察者。当内存状态发生变化时,MemoryManager负责通知这些模块,使它们能够根据当前内存状况(如正常状态或低内存状态)调整自身行为,从而避免内存不足导致的应用崩溃。
java
public interface MemoryManager {
/**
* Classes implementing this interface will be able to get updates about
* memory status changes.
*/
public static interface MemoryListener {
/**
* Called when the app is experiencing a change in memory state. Modules
* should listen to these to not exceed the available memory.
*
* @param state the new state, one of {@link MemoryManager#STATE_OK},
* {@link MemoryManager#STATE_LOW_MEMORY},
*/
public void onMemoryStateChanged(int state);
/**
* Called when the system is about to kill our app due to high memory
* load.
*/
public void onLowMemory();
}
/** The memory status is OK. The app can function as normal. */
public static final int STATE_OK = 0;
/** The memory is running low. E.g. no new media should be captured. */
public static final int STATE_LOW_MEMORY = 1;
/**
* Add a new listener that is informed about upcoming memory events.
*/
public void addListener(MemoryListener listener);
/**
* Removes an already registered listener.
*/
public void removeListener(MemoryListener listener);
/**
* Returns the maximum amount of memory allowed to be allocated in native
* code by our app (in megabytes).
*/
public int getMaxAllowedNativeMemoryAllocation();
/**
* Queries the memory consumed, total memory, and memory thresholds for this app.
*
* @return HashMap containing memory metrics keyed by string labels
* defined in {@link MemoryQuery}.
*/
public HashMap queryMemory();
}
两者之间的直接联系体现在MemoryManager接口中定义的queryMemory()方法,这个方法明确要求返回一个使用MemoryQuery中定义的标准键值格式的HashMap。这意味着任何实现了MemoryManager接口的具体类都需要依赖MemoryQuery或类似工具来获取标准化内存数据。这种设计使得系统能够保持高度模块化------MemoryQuery专注于数据准确性,而MemoryManager专注于状态管理和模块协调。
java
public HashMap queryMemory() {
// Get ActivityManager.MemoryInfo.
int memoryClass = mActivityManager.getMemoryClass();
int largeMemoryClass = mActivityManager.getLargeMemoryClass();
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
mActivityManager.getMemoryInfo(memoryInfo);
long availMem = memoryInfo.availMem / BYTES_IN_MEGABYTE;
long totalMem = memoryInfo.totalMem / BYTES_IN_MEGABYTE;
long threshold = memoryInfo.threshold / BYTES_IN_MEGABYTE;
boolean lowMemory = memoryInfo.lowMemory;
// Get ActivityManager.RunningAppProcessInfo.
ActivityManager.RunningAppProcessInfo info = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(info);
// Retrieve a list of all running processes. Get the app PID.
int appPID = Process.myPid();
// Get ActivityManager.getProcessMemoryInfo for the app PID.
long timestamp = SystemClock.elapsedRealtime();
long totalPrivateDirty = 0L;
long totalSharedDirty = 0L;
long totalPSS = 0L;
long nativePSS = 0L;
long dalvikPSS = 0L;
long otherPSS = 0L;
if (appPID != 0) {
int pids[] = new int[1];
pids[0] = appPID;
Debug.MemoryInfo[] memoryInfoArray = mActivityManager.getProcessMemoryInfo(pids);
totalPrivateDirty = memoryInfoArray[0].getTotalPrivateDirty() / BYTES_IN_KILOBYTE;
totalSharedDirty = memoryInfoArray[0].getTotalSharedDirty() / BYTES_IN_KILOBYTE;
totalPSS = memoryInfoArray[0].getTotalPss() / BYTES_IN_KILOBYTE;
nativePSS = memoryInfoArray[0].nativePss / BYTES_IN_KILOBYTE;
dalvikPSS = memoryInfoArray[0].dalvikPss / BYTES_IN_KILOBYTE;
otherPSS = memoryInfoArray[0].otherPss / BYTES_IN_KILOBYTE;
}
HashMap outputData = new HashMap();
outputData.put(KEY_TIMESTAMP, new Long(timestamp));
outputData.put(KEY_MEMORY_AVAILABLE, new Long(availMem));
outputData.put(KEY_TOTAL_MEMORY, new Long(totalMem));
outputData.put(KEY_TOTAL_PSS, new Long(totalPSS));
outputData.put(KEY_LAST_TRIM_LEVEL, new Integer(info.lastTrimLevel));
outputData.put(KEY_TOTAL_PRIVATE_DIRTY, new Long(totalPrivateDirty));
outputData.put(KEY_TOTAL_SHARED_DIRTY, new Long(totalSharedDirty));
outputData.put(KEY_MEMORY_CLASS, new Long(memoryClass));
outputData.put(KEY_LARGE_MEMORY_CLASS, new Long(largeMemoryClass));
outputData.put(KEY_NATIVE_PSS, new Long(nativePSS));
outputData.put(KEY_DALVIK_PSS, new Long(dalvikPSS));
outputData.put(KEY_OTHER_PSS, new Long(otherPSS));
outputData.put(KEY_THRESHOLD, new Long(threshold));
outputData.put(KEY_LOW_MEMORY, new Boolean(lowMemory));
Log.d(TAG, String.format("timestamp=%d, availMem=%d, totalMem=%d, totalPSS=%d, " +
"lastTrimLevel=%d, largeMemoryClass=%d, nativePSS=%d, dalvikPSS=%d, otherPSS=%d," +
"threshold=%d, lowMemory=%s", timestamp, availMem, totalMem, totalPSS,
info.lastTrimLevel, largeMemoryClass, nativePSS, dalvikPSS, otherPSS,
threshold, lowMemory));
return outputData;
}
在实际运行中,这两个类协同工作形成了一个完整的内存管理闭环:系统内存状态变化首先被MemoryManager监控到,然后通过调用MemoryQuery的详细数据采集方法获取当前内存快照,最后MemoryManager根据这些数据判断是否需要触发状态变化通知,从而引导各个功能模块采取相应的内存优化措施。这种设计不仅确保了内存敏感型应用(如相机)的稳定运行,也为性能优化和问题排查提供了坚实的数据基础,充分体现了良好的软件架构设计原则。