1

我现在正在调查遗留 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 确实按预期工作,所以我认为调试器有问题。在对象视图中,我也进行了一些重置。

4

1 回答 1

1

我看到每个“get”调用expandGroup,每个insert 调用createGroup。我认为这些功能没有任何提高效率的尝试。这意味着他们每次都复制对象,即使没有必要。

使用这些对象的代码是否在修改它们?或者,如果有修改,你能缩小范围,让那些案例使用 'getMutable' 吗?如果您可以执行其中任何一项,您将能够从 insertAt 函数中删除“createGroup”,并从 get 函数中删除“expandGroup”,并保存对象副本。

于 2013-07-20T19:16:51.613 回答