We are about to switch to a new forum software. Until then we have removed the registration on this forum.
For some reason every image i use on my sketch stays in memory untill i close the sketch. Even if i null-reference all of the variables, the Garbage Collection can't release them.
I've came across with a lot of forum posts about it and all suggested g.removeCache( PImage)
but this doesn't work. Also, even if i don't use image()
in my sketch, it still consumes a lot of memory. Just comment it out and you will see that loadImage()
puts the image on the Heap Memory and even if you null reference the img variable it will not make a difference in the memory usage.
(for this sketch i'm using an 40mb .png i've created in mspaint)
`PImage img;
void setup() {
size(200, 200);
img = loadImage("big.png");
}
void draw() {
clear();
if(img!=null){
image(img, 0, 0);
g.removeCache( img );
img = null;
println("cleaned");
};
System.gc();
}
void keyPressed(){
if(key=='q'){
g.removeCache( img );
img = null;
}
} `
Also, System.gc()
doesn't work. How can i release those images from the memory?
Answers
@Henri -- Interesting. Thank you for documenting clearly. If nobody has a solution, perhaps report this as an issue to Processing Issues....
I'm not sure what you're describing is a bug. Consider this program:
Here I'm loading a 7MB file every single frame, then measuring the memory consumption. If there really was a bug where
PImage
memory was never reclaimed, I would expect this to run out of memory pretty fast. However, I end up with the "sawtooth" usage that is perfectly normal for a Java application:If I add a call to
g.removeCache(img);
andSystem.gc();
at the end of thedraw()
function, then memory usage is 41% for the entire duration of the program.Keep in mind that
System.gc()
only suggests that garbage collection be done. If you aren't running out of memory, then this isn't a bug, and Java is functioning as expected.Also note that according to the Processing source code, the image cache is a
WeakHashMap
, so you don't need to do anything special to clear the cache. It will be cleared if you're running low on memory. If you aren't running low on memory, then it won't be cleared. This is exactly the behavior I would expect.If you can create a program that runs out of memory (which it should do at 256 MB), then that's probably a bug and we can go from there.
Indeed KevinWorkman, this sketch doesn't run out of memory.
I have been using windows Task Manager to keep track of memory. I tried adding
totalMem()
andusedMem()
on my code and indeed it shows a different information than Task Manager.Processing sketch: prints 90%, then after
img = null
it prints 32%.Task Manager: Goes up to 1.465 MB of Ram and program start and stays there until sketch is closed.
Is this expected behaviour? I use mostly Processing and i've never used "vanilla" Java.
Also, indeed without both
g.removeCache()
andSystem.gc()
the sketch keeps printing 91%. And curously enough if i use System.gc() only once memory only drops to 61%. I must use it outside thefor(){}
in order for memory to drop to 31%. (see code, Lines 18 and 23). Is this also expected behaviour?As mentioned, Java language doesn't guarantee gc() to work all the time.
But in my experience, gc() does an "honest" effort to get rid of all orphan objects when called. [-O<
Java hides a lot of the underlying memory management from you, and for the most part that's a good thing. But that can make it hard to answer questions like "is this expected behavior?"
Basically, if you aren't running out of memory, then Java is working as expected. Looking too closely at how much memory is being used at any particular time can be a bit of a wild goose chase.
Java will run the garbage collector
whenever it damn well pleasesat regular intervals and whenever it detects that you're about to run out of memory. You don't have any control over it, and you can't make any predictions about it other than it'll run the garbage collector before it runs out of memory.That being said, it's not like Java will just eat up all your memory. By default, Java is limited to taking up 256 MB of memory, and whenever it starts to reach that limit, it will run the garbage collector. Worrying about a few MB of memory in either direction isn't really worth your time.
I think everything is working exactly as intended in this case.
If I remember correctly
System. gc()
does not perform garbage collection it simply requests the Java runtime to do it when convenient.As mentioned, my experience w/ gc() is that it simply works all the time.
Of course the docs insist it's not guaranteed. But in practice it does! \m/
From the Java API, emphasis mine:
A lot of factors go into garbage collection, and at the end of the day we can't be absolutely positive what it's doing. Notice that in my dumb tests, calling
System.gc()
actually causes the overall program to use more memory than just letting Java handle it. So it's not as simple as saying that this method definitely does or does not run garbage collection.At the end of the day, the moral of the story is the same: if you aren't running out of memory, don't worry about it.
I've did some tests and indeed i'm not running out of memory. But out of curiosity
why Window's task manager shows a different memory consumption value? If i, for ex, open another app like Photoshop that uses a lot of memory, would it be able to use the released memory?
why the difference between using
System.gc()
in lines 18 and 23 gives different results?It depends, and honestly "the Java answer" is that you shouldn't really care about this low-level stuff. What exactly do you mean that the task manager shows a different memory consumption value? What is the value, and what is it different from?
If I understand the question, then the answer is yes, once memory is freed up via garbage collection then the computer can use that memory for other stuff. It's a little more complicated than that, but basically garbage collection is doing its job and you shouldn't have to worry about it.
Again,
System.gc()
only makes a suggestion, so you shouldn't worry too much about exact numbers. But I will point out that line 18 happens before you setimg
tonull
, soimg
can't be garbage collected yet.Using 2.2.1 and getting out of memory when i run sketch. basically it asks the user to grab an image. The image is then loaded with loadImage() After 1000's of draw loops , i get out of memory and sketch halts with error messages in console. Is the auto memory management in Java the same in this version or better in later versions of Processing? The program uses an event counter to allow only one iteration of each condition in the draw loop. Step 1 - wait for user to request image grab Step 2 - loadImage and display with image() Step 3- perform image processing Step 4- report numeric results ( count all pixels below threshold) Reset event counter to 1
I inserted a wait time of 1 second to auto initiate the loop and it runs for hours and finally gives out of memory So is the garbage collector not working in theis version or what?
Thanks
So this is NOT true?
My initial reasoning was that :
PImage screenImage;
was defined as a global variable, and so each time I used:
screenImage = loadImage("screen.png"); inside draw
the new image would be loaded into the screenImage variable memory space, not take new memory!
Variables (also fields & parameters) AREN'T objects! Non-primitive variables simply store a value (4 or 8 bytes) which represents the 1st memory address of a contiguous block of memory (an object).
More than 1 variable (or even array slots) can point to the same object, becoming aliases to it.
That is, they'd all store the same memory address value.
If an object doesn't have any variable, field or array slot storing its memory address value, it becomes eligible to be garbage-collected at some point in time later.