我现在正在调查遗留 BB7 应用程序中的内存泄漏,该应用程序最初由不再在公司的开发人员为 OS 4.5 开发。这个洞太大了,设备会随着时间的推移而退化,并在使用几个小时后使设备处于呆滞状态。它变慢了,因为可怕的黑色时钟出现在屏幕上,并且频率越来越高,以便进行简单的操作。我已经通过调试器确认垃圾收集器启动时会出现黑色时钟,并且在这些时间间隔内没有进行其他繁重的处理。显然,这些自动 GC 操作并不能缓解内存短缺。
我已经使用 BlackBerry Objects View in BB plugin for eclipse 检查了进程应用程序内存。我没有在这个过程中看到任何类型的异常数量的实例。有趣的是,尽管是由该应用程序进程创建的,但模型中的大量类实例似乎都存在于根进程 RAM (pid=0) 中。并且它们似乎是由于对保存它们的持久向量的迭代而泄露的(例如:持久存储中只有 100 个实例,但在对持久向量进行几次迭代后,根进程 RAM 中有 2000 个实例。显然1900 个额外的实例是已经存在的实例的克隆)。打开调试器后,我可以看到实例不断堆积在 RAM 中,并且没有被我在控制台中看到的简短自动 GC 收集,
主要嫌疑人是一个 DAO 类,它RuntimeStore
作为一个单例实例保存(也必须从备用入口点调用)。BigVector
它包含对保存在 中的a 的引用PersistentStore
,并包含上述模型类的实例。这是一个缩短的版本:
public class LeakyDAO {
private long persistentStoreId;
private long runtimeStoreId;
private PersistentObject persistentObject;
private BigVector bigVector;
private LeakyDAO(long id_p, long id_r) {
persistentStoreId = id_p;
runtimeStoreId = id_r;
persistentObject = PersistentStore.getPersistentObject(persistentStoreId);
Object o = persistentObject.getContents();
if(o instanceof BigVector){
bigVector = (BigVector) o;
} else {
bigVector = new BigVector();
persistentObject.setContents(bigVector);
}
}
public static synchronized LeakyDAO getInstance(long idPersist, long idRuntime) {
RuntimeStore rs = RuntimeStore.getRuntimeStore();
LeakyDAO dao = (LeakyDAO) rs.get(idRuntime);
if (dao == null) {
dao = new LeakyDAO(idPersist, idRuntime);
try {
rs.put(idRuntime, dao);
} catch (IllegalArgumentException e) {
//Already exists
}
}
return dao;
}
public synchronized Object get(int index) {
return ObjectGroup.expandGroup(bigVector.elementAt(index));
}
public synchronized void insertAt(int index, Persistable p) {
ObjectGroup.createGroupIgnoreTooBig(p);
if (index >= bigVector.size()) {
bigVector.addElement(p);
} else {
bigVector.insertElementAt(p, index);
}
persistentObject.setContents(bigVector);
persistentObject.commit();
}
}
我忽略的这门课有什么可怕的错误吗?在这一点上,我还不能确认这些实例实际上是问题的原因,因为应用程序在插入调试器时的行为非常不同。但是有没有可能,由于操作系统中的错误(或已知行为),某些实例在重复调用后被泄露,get
或者insertAt
?
更新
只有在调试器打开时才会观察到自动垃圾收集和一些 OutOfMemoryErrors 的问题。当它不处于调试模式时,自动 GC 确实按预期工作,所以我认为调试器有问题。在对象视图中,我也进行了一些重置。