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