AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79556357
Accepted
Schmaehgrunza
Schmaehgrunza
Asked: 2025-04-05 07:12:21 +0800 CST2025-04-05 07:12:21 +0800 CST 2025-04-05 07:12:21 +0800 CST

Memória Crescendo em CJS

  • 772

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

insira a descrição da imagem aqui

insira a descrição da imagem aqui

gjs
  • 2 2 respostas
  • 35 Views

2 respostas

  • Voted
  1. Best Answer
    ptomato
    2025-04-06T06:46:28+08:002025-04-06T06:46:28+08:00

    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.

    • 1
  2. Schmaehgrunza
    2025-04-05T22:54:49+08:002025-04-05T22:54:49+08:00

    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:

    #!/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 finalize_destroy (button)
        {
        buttons[button.index]=null;
        }
    
    function construct_buttons ()
       {
       for (let i=0;i<500;i++)
          {
          button=new Gtk.Button ({label:"hello"});
          box.add (button);
          button.index=i;
          button.connect ("destroy", finalize_destroy)
          buttons.push (button);
          }
       }
       
    setInterval (function ()   
       {
       if (remove)
          {
          for (let i=0;i<500;i++) buttons[i].destroy ();
          buttons=[];
          }
       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 ();
    

    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:

    #!/usr/bin/cjs
    "use strict";
    import Gtk from 'gi://Gtk?version=3.0';
     
    Gtk.init (null);
    
    const window=  new Gtk.Window ();
    let top_box=new Gtk.Box ({ orientation:1}), own_widgets= [], remove=true;
    
    //-- constructor own widgets: which is a collection of structured gtk widgets
    function OwnWidget ()
       {
       var widgets=new Object ();
       
       //-- collecting all widgets i construct in container namespace widgets
       widgets.eventbox_for_hbox= new Gtk.EventBox ();                                                           
        widgets.eventbox_for_vbox= new Gtk.EventBox ({halign:1,valign:1});                                          
        widgets.hbox=              new Gtk.Box ({ spacing: 2});
        widgets.vbox=              new Gtk.Box ({ orientation:1, spacing: 2});
        widgets.button_A=          new Gtk.Button ({ label:"Button_A", halign:3, valign:3 }),         
        widgets.button_B=          new Gtk.Button ({ label:"Button_B", halign:3, valign:3 }), 
        widgets.button_C=          new Gtk.Button ({ label:"Button_C", halign:3, valign:3 }), 
       
       //-- some structure: eventbox_for_vbox (top container) -> vbox -> eventbox_for_hbox -> hbox -> buttons                                       
            widgets.hbox.add(widgets.button_A);
            widgets.hbox.add(widgets.button_B);
            widgets.hbox.add(widgets.button_C);
            widgets.eventbox_for_hbox.add (widgets.hbox);
        widgets.vbox.add (widgets.eventbox_for_hbox);
        widgets.eventbox_for_vbox.add (widgets.vbox);
        
        /* connecting destroy handler for every widget -> OwnWidget.prototype.destroy.finalize_destroy is the template function
           and adding a property to every widget called OWNWIDGET_propertyID, which is the widgets property name in the "widgets" object.
           This is needed in finalie_destroy see below. */
        for (let propertyID in widgets)
           {
           widgets[propertyID].connect ("destroy", OwnWidget.prototype.destroy.finalize_destroy.bind (this));
           widgets[propertyID].OWNWIDGET_propertyID=propertyID;
           }
           
        this.widgets=widgets;
        this.top_container=widgets.eventbox_for_vbox;
       }
    
    //-- destroys your own widget
    OwnWidget.prototype.destroy=function ()
       {
       this.top_container.destroy ();
       this.top_container=null;
       }
    
    //-- called on signal destroy, releaving the references of GJS in instance.widgets object
    OwnWidget.prototype.destroy.finalize_destroy=function destroy (widget)
       {
       this.widgets[widget.OWNWIDGET_propertyID]=null;
       }
       
    //-- construct 100 own widgets with the above structure
    function construct ()
       {
       let own_widget;
     
       for (let i=0;i<250;i++)
          {
          own_widget=new OwnWidget ();
          top_box.add (own_widget.widgets.eventbox_for_vbox);
          own_widgets[i]=own_widget;
          }
       window.show_all();
       }
    
    //-- removes the 100 own widgets from the top-box and destroys it
    function remove_and_destroy ()
       {
       for (let i=0;i<250;i++) 
          {
          own_widgets[i].destroy ();
          /* to be sure, that all is freed, i also set the array reference on the own widget instance null,
             but this will be overwritten by the next construct () call, so i think its not necessary. */
          own_widgets[i]=null;
          }
       }
     
    setInterval (function ()   
       {
       if (remove) remove_and_destroy ();
       else construct ();
    
       remove=!remove;
       }, 3000);
    
    construct ();
    window.add(top_box);
    window.set_title ("Test");
    window.connect ('destroy', () => { Gtk.main_quit (); });
    window.set_size_request (740, 600);
    window.show_all ();
    
    Gtk.main ();
    
    • 0

relate perguntas

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve