Tenho problemas com vazamentos de memória, então fiz o seguinte código de teste.
#!/usr/bin/cjs
"use strict";
import Gtk from 'gi://Gtk?version=3.0';
Gtk.init (null);
const window= new Gtk.Window ();
let buttons=[], button, box=new Gtk.Box ({ orientation:1}), remove=true;
function construct_buttons ()
{
for (let i=0;i<500;i++)
{
button=new Gtk.Button ({label:"hello"});
box.add (button);
buttons.push (button);
}
}
setInterval (function ()
{
if (remove)
{
for (let i=0;i<500;i++) buttons[i].destroy ();
buttons=[], button=null;
}
else
{
construct_buttons ();
window.show_all ();
}
remove=!remove;
}, 2000);
construct_buttons ();
window.add(box);
window.set_title ("Test");
window.connect ('destroy', () => { Gtk.main_quit (); });
window.set_size_request (740, 600);
window.show_all ();
Gtk.main ();
Eu construo 500 botões e os adiciono a uma caixa. Após 2 segundos, eu os destruo com Gtk.widget.destroy() e libero o array de referência buttons=[], button=null, e após 2 segundos eu os construo novamente e assim por diante.
Fazendo isso por um tempo, minha memória cresceu de 17 MiB para mais de 50 MiB. Então parei. Não consigo descobrir o que estou fazendo errado. Tenho o mesmo problema com um aplicativo maior. Este é apenas um pequeno exemplo para teste.
Eu também tentei em vez de destruir. Gtk.widget.remove (widget), e deixei o cjs destruí-lo, mas aqui também a memória cresce.
Eu tenho o cjs versão 6.0.0
Analisei o programa original com a ferramenta heapgraph . Após remover os 500 botões, eles ficam visíveis no heap dump, mas marcados como "inacessíveis". Então eles não estão vazando, eles serão apenas removidos na próxima coleta de lixo.
O problema parece ser que o coletor de lixo não está sendo acionado. Este é provavelmente o problema conhecido https://gitlab.gnome.org/GNOME/gjs/-/issues/52 . Por enquanto, você pode acionar a coleta de lixo manualmente adicionando
imports.system.gc()
depois de destruir os botões e anulando as referências. Se eu adicionar essa linha ao script original, o uso de memória nunca ultrapassa 19 MB, mesmo criando botões duas vezes mais rápido e executando por 10 minutos.Ok, depois de testar por horas, eu consegui..
Eu tenho que liberar a referência mantida pelo GJS em um manipulador de sinal de destruição, todas as outras tentativas resultam em vazamentos de memória.
Eu não sei por que, mas simplesmente definir suas referências no GJS como nulas depois de usar Gtk.widget.destroy() não funciona e se você tentar remover o elemento primeiro do pai e então definir sua referência como nula e deixar o GJS destruí-lo, também resulta em vazamentos de memória.
Isso funciona:
Então, se eu construir meu próprio widget, que consiste em muitos widgets Gtk, eu coleto todos os widgets em um objeto contêiner de namespace "widgets".
Após a construção, eu conecto um manipulador para cada widget ao sinal destroy e libero as referências no manipulador destroy.
Não sei se essa é a maneira correta, mas funciona.
Um exemplo mais complexo: