Hans Passant was correct. The issue was a bitmap that was being duplicated, though it's still not clear to me why this was causing the garbage collector to apparently fail to do its job.
I have some back-end classes in this program which take images from cameras and convert the bitmaps to the appropriate format (for example, the YUV422 to RGB conversion I posted). The bitmap that gets passed around is reused.
Then I have some UI classes, one of which is a window which displays a fresh frame on a timer running at more or less 10 Hz. Here you must copy the Bitmap since the back end stuff will be replacing it with a new frame, etc.
The routine to update the display was simple:
public void SetImage(Bitmap Image)
{
if (this.IsDisposed) return;
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { SetImage(Image); });
else
picFrame.Image = (Bitmap)Image.Clone();
}
One camera gives 640x480x8 bit (black and white) images; on the back end I also use lockbits to copy the array of pixels I get from the API calls to a .NET bitmap. I had no issues with memory even with two of these cameras (and display windows) running at once.
The 1920x1080 YUV422 image was obviously "saturating" (or however you'd call it) the garbage collector so that this version of the display routine fixed the problem:
private Bitmap DisplayImage = null;
public void SetImage(Bitmap Image)
{
if (this.IsDisposed) return;
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { SetImage(Image); });
else
{
if (DisplayImage != null)
DisplayImage.Dispose();
DisplayImage = (Bitmap)Image.Clone();
picFrame.Image = DisplayImage;
}
}
What threw me is that watching the memory usage with the black and white cameras only revealed it was nailed around some low number, while the color camera alone was skyrocketing toward 2 GB with no signs of stopping. I've seen borderline garbage collector cases where you see the memory creep up and then suddenly come back down when the garbage collector kicks in.
The clear difference here is of course that even two black and white cameras are only 614kB x 10 fps, whereas the color camera is some 10 times that. I am not even going to begin to conjecture why the former had no issues with the garbage collector and the latter did.