3

So I've been trying to get a memory intensive program to work, and kept running into memory errors. I've read the other threads, and they all talk about memory leaks, but I don't think that is the case here.

I created a button that allocates 1 megabyte of space, then displays the memory usage in megabytes (maxmem, totalmem, freemem). Initially i have (40, 5, 2), I press the button (40, 6, 2). I keep pressing the button and I get (40, 7, 2), (40, 8, 2), (40, 9, 2), then OutOfMemory. I would expect (40, 10, 2) and shouldn't get OutOfMemory until I hit (40, 40, 0), right?

int[][] hi = new int[100][];
int i = 0;

public void save(View view) {
    hi[i] = new int[256*1024];
    i++;
    TextView tv1 = (TextView) findViewById(R.id.seekBar1Text);
    System.gc();
    tv1.setText("Memory is max " + Runtime.getRuntime().maxMemory()/1024/1024 + " total " + Runtime.getRuntime().totalMemory()/1024/1024 + " free " + Runtime.getRuntime().freeMemory()/1024/1024);
}
droideka-coder
  • 259
  • 1
  • 2
  • 5
  • 1
    CommonsWare may be right with the Android memory measurement. Directly before this button appears in my app, I load a photo into bitmap ARGB format, which should take about 20MB of memory, yet this memory is greater than "total memory." So I guess the bitmap wasn't counted, but still took up space. By not loading this photo, I was able to allocate much more memory, up to about 38MB of the 40MB. – droideka-coder Feb 19 '12 at 18:08

4 Answers4

3

I notice that Dianne Hackborn's definitive answer on Android memory measurement does not use the Runtime methods. Hence, I do not know if I would trust them. For starters, I know of no Android device with a 40MB heap size.

Also, you seem to assume that an OutOfMemoryError means that you are fully out of memory. An OutOfMemoryError will occur when an attempted allocation fails. That could be because there is no single free block of the size you seek. This is more likely to happen on Android than with other operating systems due to the nature of the Dalvik VM's GC routines.

Community
  • 1
  • 1
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
2

Interesting problem. I have been playing around with this in various Android versions (emulated), and tried it out on my own machine. I can see the behavior you expect (memory filling up, and only then crashing) on Android 3.1, but 2.2 shows the behavior you describe.

As @CommonsWare states, it most likely has to do with the huge block of memory you request: even on my machine, I cannot allocate an array that has 4*256*1024 elements (remember that this array has to be indexable, so it has be contiguous somehow).

The best solution seems to be not to allocate less memory, but to allocate not as much as the same time. In Android 2.2, I can fill up the memory using blocks of 16*1024 without any problems.

The exact solution depends on the specifics of your application. For instance,

  • If you're processing incoming data, you could try keeping less of it in memory, and using stream processing.
  • If you really need the data, you could consider different structures (that don't require contiguous blocks).
  • If all else fails, you can always build some helper classes that give the impression of a contiguous block of memory, while actually chunking it into smaller parts.
Angelo van der Sijpt
  • 3,611
  • 18
  • 24
1

In the JVM, it places large structures directly into a tenured space. If it can;t resize this space (or its too fragmented) you can run out of available space for these structures even though there is plenty of free space. Sometimes tuning the VM can help.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
0

On my emulator (set to API 10) I used this:

Runtime rt = Runtime.getRuntime();

rt.gc(); // cause garbage collection for better accuracy

int[][] i = new int[4024][2014]; // a blob from hell to cause OOM crash and Force Close 

long max = rt.maxMemory(); // max that can be allocated (more than max gets you OOM crash)

long total = rt.totalMemory(); // this is total in use, not total possible

long free = rt.freeMemory();    

long used = (total - free); 

s = "RAM:" + String.format("%.0fKB, %.0fU, %.0fF", 
                           max / 1024.0, used / 1024.0, free / 1024.0); 

I got a crash, because blob + app were slightly larger than emulator's 24MB limit. I still don't fully get the memory issues though. Seems that Android/Java world is more complex than the Linux/C world when it comes to memory stuff.

dandan78
  • 13,328
  • 13
  • 64
  • 78