我正在调查传统BB7应用程序中的内存泄漏,该应用程序最初是由不再在公司的开发人员为OS 4.5开发的。孔太大,设备会随着时间的推移而降低,并且在几小时的使用中将设备置于缓慢的状态。它变慢了,因为可怕的黑色时钟出现在屏幕上,频率越来越高,操作简单。我已经向调试器确认当垃圾收集器启动时出现黑色时钟,并且在这些间隔期间没有发生其他重处理。显然,这些自动GC操作不会减少内存不足。
我已经使用BB插件中的BlackBerry Objects View检查了流程应用内存。我没有在这个过程中看到任何类型的异常实例。有趣的是,尽管由此应用程序进程创建,但模型中的大量实例似乎仍存在于根进程RAM(pid = 0)中。并且它们似乎是由于对持有它们的持久向量的迭代而泄露(例如:持久存储中只有100个实例,但是在持久向量上经过几次迭代后,根进程RAM中有2000个实例。显然1900个额外的实例是已经处于持久性中的克隆。 启用调试器后,我可以看到实例在RAM中堆积并且不会被我在控制台中看到的简短自动GC收集,但是当我从调试器手动强制GC时它们被删除(这需要相当长的时间)跑)。
主要嫌疑人是一个DAO类,它作为单例实例保存在RuntimeStore
中(也必须从备用入口点调用)。它包含对BigVector
中保存的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
之后泄露了某些实例?
UPDATE
只有在调试器打开时才会观察到自动垃圾收集和一些OutOfMemoryErrors的问题。当它不处于调试模式时,自动GC确实按预期工作,所以我认为调试器存在问题。在对象视图中我也进行了一些重置。
答案 0 :(得分:1)
我看到每个'get'调用expandGroup,每个insert都调用createGroup。我不认为这些功能会有效提高效率。这意味着他们每次都复制对象,即使没有必要。
使用这些对象的代码是否会修改它们?或者,如果有修改,你可以缩小它,并使这些情况使用'getMutable'吗? 如果你可以做其中任何一个,你将能够从insertAt函数中删除'createGroup',并从get函数中删除'expandGroup',并保存在对象副本上。