私は現在、会社にいない開発者によって OS 4.5 用に開発されたレガシー BB7 アプリのメモリ リークを調査しています。穴は非常に大きいため、時間の経過とともにデバイスが劣化し、数時間の使用でデバイスが動きが鈍い状態になります。恐ろしい黒い時計が画面に表示され、単純な操作の頻度が高くなるため、速度が低下します。デバッガーで確認したところ、ガベージ コレクターが起動すると黒い時計が表示され、その間に他の重い処理は行われていません。明らかに、これらの自動 GC 操作はメモリ不足を緩和しません。
BlackBerry Objects View in BB plugin for eclipse を使用して、プロセス アプリのメモリを調べました。このプロセス内で異常な数のインスタンスが発生したことはありません。興味深いことに、モデルのクラスの多数のインスタンスが、このアプリ プロセスによって作成されたにもかかわらず、ルート プロセス RAM (pid=0) に存在しているように見えます。また、それらを保持する永続ベクトルの反復によりリークしているように見えます (たとえば、永続ストアには 100 個のインスタンスしかありませんが、永続ベクトルを数回反復した後、ルート プロセス RAM に 2000 インスタンスが存在します。明らかに1900 の余分なインスタンスは、すでに永続化されているインスタンスのクローンです)。デバッガーをオンにすると、インスタンスが RAM に蓄積され続け、コンソールに表示される簡単な自動 GC によって収集されないことがわかります。
主な容疑者は、RuntimeStore
シングルトン インスタンスとして保持されている DAO クラスです (別のエントリ ポイントからも呼び出す必要があります)。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();
}
}
私が見落としているこのクラスについて何かひどく間違っていることはありますか? 現時点では、これらのインスタンスが実際に問題の原因であることを確認することはできません。これは、デバッガーにプラグインしたときのアプリの動作がまったく異なるためです。しかし、OS のバグ (または既知の動作) が原因で、繰り返し呼び出した後に一部のインスタンスがリークしている可能性はありますget
かinsertAt
?
更新
自動ガベージ コレクションといくつかの OutOfMemoryErrors に関する問題は、デバッガがオンの場合にのみ観察されます。デバッグモードではない場合、自動 GC は期待どおりに動作するので、デバッガーに問題があると思います。オブジェクト ビューでは、いくつかのリセットも行いました。