1) Load a 2048x2048 image into memory.2) Copy that image onto a total of 16 512x512 tiles of that image (which are also images).3) Garbage collect #1.4) So numbers 1 and 2 a total of 4 times, each time deleting 1 but keeping all the results of 2.

This means that, at the most, there will be BufferedImage's totaling:1 2048x2048 TYPE_INT_ARGB64 512x512 TYPE_INT_ARGB

That's a lot. I've jacked up the heap size to 1024 and it still can't handle anything past the second pass (it craps out at 1 2048x2048 and 21 512x512).

Any ideas on how I can actually make this happen? If I use a different BufferedImage type will that be cheaper? These are background images, so I won't really be needing TYPE_INT_ARGB.

How do you know it's really garbage collected? I've had some issues in the past with BufferedImages that basically refused to be garbage collected (possibly because they were still being hardware accelerated and as such still referenced somewhere internally in Java 2D, but that's just guessing).

Here's the code. I wasn't at all sure the garbage collector was taking the image away - it probably wasn't. Just for reference, bFiles has length of 4 and just points to 4 different PNG images that are 2048x2048.

I'm guessing that using getGraphics() and drawImage() within that is not just taking the part within bounds, and is somehow storing the stuff outside of it, so I end up with like 25 2048x2048? I know there are lots of better ways to do this, but I've got a deadline with this thing so I've written it all quick n' dirty. Also, this is one part of a big UI, in which there are probably like 50 icon-sized (32x32 or 64x64) images loaded and 20 larger images (256x256) loaded.

Changed my code to set the RGB values directly and not only was it significantly faster but it also made it further before it crapped out. Nevertheless, it broke after almost 3 iterations (so somewhere around 45 512x512 had been loaded, plus 1 2048x2048).

Also, I'm using Java 5 if that makes a difference. And I edited my code above to match the pixel setting method instead of using Graphics.

I took your code and ran it in a runnable test case. When I used Java 6 on my Mac, it ran to completion and the heap size of the jvm was 80.5 Mb (reported memory usage was 79.33 M). However when I tested it with the default jvm, it crashed after using about 62 M. When I increased the heap size to 128m, Java 5 ran it to completion as well, although its reported heap usage was 80.6 out of 127.06 M.

I didn't modify your code, so I'm not sure why it's failing on your computer, unless integration with the UI is consuming a lot more resources??

Now this is really ticking me off. I commented out almost all the UI elements getting initialized and I get just a few more tiles loaded before it gets a heap error. This is seriously irritating. I can't believe how inefficient BufferedImage's are... I've almost always had problems with them.

Also, this is probably a noob question, but how are you seeing how much heap is being used?

Quote

The problem you encountered is typically a JAVA problem.The mechanism that processes images doesn't release the used memorywhat ever you do.

Some month ago I submitted almost the same question and the solutionI found myself was to spawn an extra program to do the 'dirty' workand exit then (to release the memory).

I don't want to do that. Please tell me I don't have to goddam do that. *grumble* what a waste of my already short time...

That is more efficient than drawImage with a negative translate and clipping by image bounds.

Because I'm doing it quick and dirty. I just want to this bastard heap crap to work at this point. It looks like I either try giving myself 2gb of heap, I use something like JMagick to load the images, or I run an external process. None of which are at all optimal, all of which make me angry that I need to do that. In my opinion, this should be a pretty simple task...

[EDIT]As I don't need all the images on screen at once (the reason there are 4 is because they correspond to 90º rotations) and because this is a level editor and therefore doesn't need to be fast, I turned the background array into a 2D array and I only store the current rotation, the rest are split up as per above when you load them, but those splits are saved as temporary files ( file.deleteOnExit() ), then when you press the rotate button it reloads those images back into memory after unloading the old ones.

Quick n' dirty, quick n' dirty.

[EDIT2]Riven, I tried your way versus setRGB(), here are time comparisons for loading, splitting, and writing 4 2048x2048 images into 64 512x512 images. The total is how long it took start to finish to do everything, including redundant stuff that has nothing to do with the different methods of copying pixels. The average is the average time it took to copy one 512x512 chunk of pixels into the new BufferedImage (over all 64 iterations).

I was curious, so now I'm doing the whole thing 100 times (over 10 minutes), minus all the excess stuff. This is just pure pixel copying. A total of 1.67 billion pixels are copied. The average is how long it took, on average, to copy 260,000 pixels.

Using drawImage:Total: 277386942000 nsAvg: 39149537 ns

Using setRGB:Total: 428779703000 nsAvg: 66407857 ns

Using getRaster().setPixel() with a temporary int[] array:Total: 332476529000Avg: 51352468

Using getRaster().setPixel() without a temporary int[] array:Total: 347614522000Avg: 53646431

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org