0

當Android應用程序不在前臺時,我將事件存儲在隊列中。事件可能很多,所以我想在達到一定限度時刪除最老的,以避免內存問題。事件可以是不同的類型,我想避免刪除某些(如果不是真的需要,例如onTrimMemory())。如果鎖定,Android緩存事件會導致崩潰

public void enqueue(T event) { 
    synchronized (events) { 
     if (events.size() > 2000) { 
      for (int i = 0; i < events.size(); i++) { 
       if (canRemove(events.get(i))) { 
        events.remove(i); 
        break; 
       } 
      } 
     } 

     events.add(event); 
    } 
} 

canRemove(event)檢查Event是否可以被移除並返回true/false的事件的instanceof。

有點logcat的後給我:「跟老闆方法長期監測爭奪事件」,並經過一段時間的logcat報告

啓動阻斷GC的Alloc

等待阻塞GC的Alloc

將目標GC堆從65MB鉗制到64MB,然後在很多不同的消息之後...應用程序崩潰。

從我所瞭解的閱讀類似問題(What might be the cause of "long monitor contention event with owner method"?)的問題是,我收到了很多事件並鎖定了「太多」時間的事件。

所以問題是......我該怎麼辦?我可以通過保存上次刪除的位置並在下一次啓動for循環時對其進行優化,但我認爲這不夠。或者我可以爲不同的事件做不同的隊列,這樣我總是會刪除第一個隊列,但我總是需要將其鎖定。有什麼更好的想法

我忘了說我宣佈:private LinkedList events = new LinkedList <>();

回答

0

使用此方法

public void enqueue(T event) { 
    List<T> removable = new ArrayList<>(); 
    synchronized (events) { 
     final int size = events.size(); 
     if (size > 2000) { 
      for (int i = 0; i < size; i++) { 
       final T t = events.get(i); 
       if (canRemove(t)) { 
        removable.add(t); 
        break; 
       } 
      } 
     } 
     if (removable.size() > 0) { 
      events.removeAll(removable); 
     } 
     events.add(event); 
    } 
} 

希望,這將解決您的問題。

+0

請注意,我一次只移除一個事件增加的情況下,讓我失去了活動的最小數量。 – MoreOver

+0

我編輯我的答案,PLZ檢查知道 –

+0

謝謝。只是一個問題:考慮到事件是一個LinkedList,在鎖之外添加events.add()不會導致ConcurrentException? – MoreOver

0

我想你可以用它來代替刪除對象events.subList方法,像這樣:

public void enqueue(T event) { 
    List<T> removable = new ArrayList<>(); 
    synchronized (events) { 
     final int size = events.size(); 
     if (size > 2000) { 
      int removeSize = events.size() - 2000; 
      events = events.subList(removeSize, events.size()); 
     } 
     events.add(event); 
    } 
}