I have a small ruby on rails site, using passenger and apache. The
site is moderately successful. It allows people to upload photos. It
seems like when people upload photos, the memory is never returned, or
very late, so on a busy day I can start to use 1 GB of swap in 30
minutes.
I use the attachment_fu to handle the uploads.
Any ideas on how to use less memory and give the memory back quicker ?
Try using Enterprise Ruby (from the same people as Passenger). It can reduce your memory footprint quite a bit. However, in the case you are describing, it could just be that your app needs to be tuned. If you are doing processing on the images, you might want to put those to a background thread like delayed_job, although that process could also suck all the ram, so you might need to use monit on it to periodically restart it.
However, tuning aside, if you are finding your volume is requiring more RAM, you might need to bump your hardware to support it.
Good question. But I don't do anything like open or close. I just
save the picture on upload.
Here is the add code that is when you press submit on the form
def add
if (params[:photo])
@photo = Photo.new(params[:photo])
if @photo.save
flash[:notice] = "Picture saved"
redirect_to :controller=>'photos',:action=>'index'
end
else
@photo = Photo.new
end
end
By the looks of it (every spawned Rails process takes about 40-ish MB), you’re wildly spawning extra Rails processes for some reason. We are using attachment_fu (and paperclip for that matter) intensively in a number of our applications and have no problems with high memory usage (except the initial RMagick hit). There must be something either in your server processes (RMagick, ImageMagick, other gem, …) that’s miscompiled or outdated or you have something around the image uploading that kills your server (threads spawning). The simple fact of the matter is that something is keeping the Passenger rails process busy and it spawns new ones to cope with new incoming requests.
Pfew, that's one Rails instance just eating more and more memory indeed. Have you been able to boil it down to RMagick itself. Otherwise I would suggest leaving thumbnailing out for a second and just saving the uploaded file to see if it is in fact the thumbnailing that eats your memory. We can work our way down from there.
OK, let’s go one step further then and boil it down to RMagick (and not ImageMagick): install the mini_magick gem and change the thumbnail processor to minimagick explicitly and look at memory consumption. Since Minimagick uses the command line to process images, you should see no significant memory usage increase in your Rails instance. Also keep an eye on the total memory usage on your server and whether the imagemagick process stays around after the file has been processed (mogrify), it shouldn’t.
Does that mean I need to change any more code than is in my model ?
I did set GC.start inside Photo.save in the controller. The situation
does not go out of hand any more, but the app is using quite a lot of
memory none the less.
One more note on this. Since you seem to be just thumbnailing, you could as well use another processor if memory is valuable. If you need to do extra processing like applying filters and constructing an image out of several other ones, then you’re best off with RMagick.
There’s nothing more to it than making sure the processor (minimagick, imagescience, gd2, core image on macos x servers) is installed correctly and explicitly defining it in your model.
Otherwise attachment_fu will see if it can use one of them in this order: @@default_processors = %w(ImageScience Rmagick MiniMagick Gd2 CoreImage).