I’m working on a gnome extension and identified a memory leak. It is somewhere in the following code, which is called repeatedly in my extension in order to automatically update the color of some UI component:
updateColor() {
const shooter = new Shell.Screenshot();
const [content]: [Clutter.TextureContent] = await shooter.screenshot_stage_to_content();
const wholeScreenTexture = content.get_texture();
const area = {
x: this.pill.x - 20 * this.scaleFactor,
y: this.y,
w: this.pill.width + 40 * this.scaleFactor,
h: this.height,
};
const stream = Gio.MemoryOutputStream.new_resizable();
const pixbuf: GdkPixbuf.Pixbuf = await Shell.Screenshot.composite_to_stream( // takes around 4-14ms, most of the time 7ms
wholeScreenTexture, area.x, area.y, area.w, area.h,
this.scaleFactor, null, 0, 0, 1, stream
);
stream.close(null);
// stream.run_dispose(); // tried this, didn't fix the memory leak
const pixels = pixbuf.get_pixels();
// [...] some pure js code iterating through `pixels`, with no references
// to anything being kept after the function is done
}
This function is at the moment called at a 500ms interval and my memory (16gb) slowly is eaten up, until it’s full after maybe 5-10 minutes. If I don’t run this code, the memory leak does not occurr at all, I’ve tried this a few times.
-
Is there anything I’m doing wrong here, or any way to easily fix this?
-
If not, is there any better way to repeatedly get all pixels in a certain area in GJS? I feel like this approach with
Shell.Screenshot.composite_to_stream
is somewhat ineffective since it always PNG-encodes the image data, but I was unable to find a better way (for context: the goal of the function is to calculate the average luminance of an area).