The strangest thing with TJPEGImage.DIBNeeded
2007-09-17 14:57 i1274 [permalink]
I found out something very strange about TJPEGImage. I was investigating a report about a memory leak in an application. When operating on about 1000 images, there were unexpectedly much occurences of EOutOfMemory, while TaskManager was still reporting enough unused memory.
PerformanceMonitor to the rescue. When I watched some process parameters, the "working set" and "private bytes" reported normal values, but the "virtual bytes" skyrocketed, and hit a 2GB boundary when the EOutOfMemory exceptions turn up. I tried the normal memory-leak checks, but there were no TObject descendants or strings leaking. So I traced the thing in debug mode (F7/F8) to see at which point the virtual bytes value jumps up a bit, and it turns out to be a call to TJPEGImage.DIBNeeded. If you don't call DIBNeeded yourself, SaveToFile or TBitmap.Assign(TJpegImage) does it for you. The amount of added virtual bytes didn't go away with the Free of the TJPEGImage.
After a lot of sandboxing and testing a bunch of scenario's, it turns out there is something wrong with how TJPEGImage does its memory in threads other than the main application thread (VCL thread). Internally the JPEG unit has a lot of ported (old) C code, and may perhaps even have an included .lib with compiled code. It does its memory-handling itself apparently, so there's no way to know if it's patchable directly.
I found out a workaround, which in most cases might be acceptable. I created a new blank library project (.dll), added a unit with the code that was doing the TJPEGImage operations in the worker thread. I had this in a plain procedure in a unit already, and exported this procedure from the dll. Then I replaced the unit with a new unit that simply 'binds' to the exported procedure in the new dll. All you need to do then is make sure the dll is always available to the exe in the same directory, or in the default windows dll search path.