Unknown memory allocation when displaying pixels in Gtk.jl

,

Hi all! I have some memory allocation I don’t understand when using Gtk, and hoping for some advice.

I’ve built an application to display and tweak (many) scientifically computed 2kx2k images, and they are displayed through Gtk. In the process of optimizing it (using @time), I’ve notice some memory allocations I can’t understand. Below is a minimum working example. Is there a way I can avoid these allocations? Perhaps I should I be using something different than a GtkCanvas?

Any comments appreciated. I’m using Julia 1.7.3

Julia Version 1.7.3
Commit 742b9abb4d (2022-05-06 12:58 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin21.4.0)
  CPU: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, skylake)

and Gtk libraries

  [4c0ca9eb] Gtk v1.2.1
  [27996c0f] GtkReactive v1.0.6```

Here is an example that demonstrates the issue (I’m on Mac, but I think it happens on Win as well).

# gtk_test.jl
#
# demonstrate unwanted memory allocation from displaying images
#  on startup, no memory allocations
#  on clicking Update, memory allocated every time
#  more memory allocated once different tabs exposed
#

import Gtk
import GtkReactive

CANVAS_SIZE_PIXELS = 512 
IMAGES_SIZE_PIXELS = 2048 

function GtkFigure(width, height)
    c = Gtk.GtkCanvas()
	Gtk.set_gtk_property!(c, :width_request, width)
	Gtk.set_gtk_property!(c, :height_request, height)
    c
end

grid_win = Gtk.GtkGrid()

canvas_img_01 = GtkFigure(CANVAS_SIZE_PIXELS, CANVAS_SIZE_PIXELS)
canvas_img_02 = GtkFigure(CANVAS_SIZE_PIXELS, CANVAS_SIZE_PIXELS)
canvas_img_03 = GtkFigure(CANVAS_SIZE_PIXELS, CANVAS_SIZE_PIXELS)
canvas_img_04 = GtkFigure(CANVAS_SIZE_PIXELS, CANVAS_SIZE_PIXELS)
canvas_img_05 = GtkFigure(CANVAS_SIZE_PIXELS, CANVAS_SIZE_PIXELS)
# (an intermediate grid seems required to avoid a Gdk assert  2019-09-22 ABahm/TKnopp)
notebk_canvases = Gtk.GtkNotebook()
push!(notebk_canvases, canvas_img_01, "01")
push!(notebk_canvases, canvas_img_02, "02")
push!(notebk_canvases, canvas_img_03, "03")
push!(notebk_canvases, canvas_img_04, "04")
push!(notebk_canvases, canvas_img_05, "05")

button_update = Gtk.GtkButton("Update")

grid_notebook = Gtk.GtkGrid()
grid_notebook[1,1] = notebk_canvases

grid_win[1,1] = button_update
grid_win[1,2] = grid_notebook

# create window
win = Gtk.GtkWindow("memory allocation after clicking tabs")
push!(win, grid_win)
Gtk.showall(win)


function set_figure!(canvas, img)
    Gtk.draw(canvas) do widget
        copy!(canvas, img)
        Gtk.reveal(canvas)
    end
end

function button_update_clicked(widget)
    r = rand(IMAGES_SIZE_PIXELS,IMAGES_SIZE_PIXELS)
    @time begin 
        set_figure!(canvas_img_01, r)
        set_figure!(canvas_img_02, r)
        set_figure!(canvas_img_03, r)
        set_figure!(canvas_img_04, r)
        set_figure!(canvas_img_05, r)
    end
end
id = Gtk.signal_connect(button_update_clicked, button_update, "clicked")

# these calls report ~ "0.000004 seconds (5 allocations: 160 bytes)"
button_update_clicked(nothing)
button_update_clicked(nothing)
button_update_clicked(nothing)
button_update_clicked(nothing)
# but clicking the update button, and switching tabs starts to use memory!?

Looks to me it might be the do-block (lamba function) that is defined inside set_figure!, but I’m not sure how to re-implement it, because it depends on the canvas in scope.