Search code examples
javaandroidgarbage-collectionqueueconcurrentmodification

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


Solution

  • 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.