MoreOver MoreOver - 4 months ago 29
Java Question

Android caching events results in crashing if locking

I'm storing Events in a Queue when the Android app is not in foreground. Events can be a lot, so I'd like to remove the oldest, when I reach a certain limit, to avoid memory issues. Events can be of different type and I'd like to to avoid removing certain (if not really needed, eg. onTrimMemory()).

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) check if the Event is instanceof of something that can be removed and returns true/false.

After a bit Logcat is giving me: "long monitor contention event with owner method" and after a while Logcat reports

Starting a blocking GC Alloc

Waiting for a blocking GC Alloc

Clamp target GC heap from 65MB to 64MB and then, after a lot of different messages... the app crash.

From what I've understand reading a similar question (What might be the cause of "long monitor contention event with owner method"?) the problem is that I'm receveing a lot of Events and locking on events for "too much" time.

So the question is... what can I do? I can optimize it a bit by saving the last position I removed and the next time start the for loop from it, but I don't think it's enough. Or I can do different Queue for different Events so that I always remove the first one, but I always need to lock it. Any better idea?

I forgot to say I'm declaring: private LinkedList events = new LinkedList<>();

Answer

Use this method

   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);
    }
}

Hopefully, it will solve your issue.

Comments