UmBottesWillen
UmBottesWillen

Reputation: 107

Drop part of a List<> when encountering OutOfMemoryException

I'm writing a program that is supposed to continually push generated data into a List sensorQueue. The side effect is that I will eventually run out of memory. When that happens, I'd like drop parts of the list, in this example the first, or older, half. I imagine that if I encounter an OutOfMemeryException, I won't be able to just use sensorQueue = sensorQueue.subList((sensorQueue.size() / 2), sensorQueue.size());, so I came here looking for an answer.

My code:

public static void pushSensorData(String sensorData) {
    try {
        sensorQueue.add(parsePacket(sensorData));
    } catch (OutOfMemoryError e) {
        System.out.println("Backlog full");

        //TODO: Cut the sensorQueue in half to make room
    }
    System.out.println(sensorQueue.size());
}

Upvotes: 1

Views: 85

Answers (4)

Martin Mucha
Martin Mucha

Reputation: 3091

I think you idea is severely flawed (sorry).

There is no OutOfMemoryException, there is OutOfMemoryError only! Why that is important? Because errors leaves app in unstable state, well I'm not that sure about that claim in general, but it definitely holds for OutOfMemoryError. Because there is no guarantee, that you will be able to catch it! You can consume all of memory within you try-catch block, and OutOfMemoryError will be thrown somewhere in JDK code. So your catching is pointless.

And what is the reason for this anyways? How many messages do you want in list? Say that your message is 1MB. And your heap is 1000MB. So if we stop considering other classes, your heap size define, that your list will contain up to 1000 messages, right? Wouldn't it be easier to set heap sufficiently big for your desired number of messages, and specify message count in easier, intergral form? And if your answer is "no", then you still cannot catch OutOfMemoryError reliably, so I'd advise that your answer rather should be "yes".

If you really need to consume all what is possible, then checking memory usage in % as @fabsas recommended could be way. But I'd go with integral definition — easier to managed. Your list will contain up-to N messages.

Upvotes: 0

Ziumin
Ziumin

Reputation: 4860

The problem with subList is that it creates sublist keeping the original one in memory. However, ArrayList or other extension of AbstractList has removeRange(int fromIndex, int toIndex) which removes elements of current list, so doesn't require additional memory.

For the other List implementations there is similar remove(int index) which you can use multiple times for the same purpose.

Upvotes: 1

fabfas
fabfas

Reputation: 2228

Is there an easy way to detect an impending OutOfMemoryException then?

You can have something like below to determine MAX memory and USED memory. Using that information you can define next set of actions in your programme. e.g. reduce its size or drop some elements.

final int MEGABYTE = (1024*1024);
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
long maxMemory = heapUsage.getMax() / MEGABYTE;
long usedMemory = heapUsage.getUsed() / MEGABYTE;

Hope this would helps!

Upvotes: 1

lffloyd
lffloyd

Reputation: 333

You can drop a range of elements from a ArrayList using subList:

list.subList(from, to).clear();

Where from is the first index of the range to be removed and to is the last. In your case, you can do something like:

list.subList(0, sensorQueue.size() / 2).clear();

Note that this command will return a List.

Upvotes: -1

Related Questions