黑莓7:根进程中奇怪的内存泄漏

时间:2013-07-19 09:51:04

标签: java blackberry memory-leaks persistence

我正在调查传统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();
        }   
    }

我忽略了这堂课有什么可怕的错吗?此时我还不能确认这些实例实际上是问题的原因,因为当插入调试器时,应用程序的行为非常不同。但是,由于操作系统中的错误(或已知行为),有可能在重复调用getinsertAt之后泄露了某些实例?


UPDATE
只有在调试器打开时才会观察到自动垃圾收集和一些OutOfMemoryErrors的问题。当它不处于调试模式时,自动GC确实按预期工作,所以我认为调试器存在问题。在对象视图中我也进行了一些重置。

1 个答案:

答案 0 :(得分:1)

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

使用这些对象的代码是否会修改它们?或者,如果有修改,你可以缩小它,并使这些情况使用'getMutable'吗? 如果你可以做其中任何一个,你将能够从insertAt函数中删除'createGroup',并从get函数中删除'expandGroup',并保存在对象副本上。