7 Replies Latest reply on Jul 7, 2013 12:08 AM by Trevorׅ

    Deleting a palette form a Session Targetengine

    Trevorׅ Adobe Community Professional

      Hi all,

       

      Does anyone know how to delete a palette from a sessions memory.

      I have a palette which after it closes I want that it should remove itself from the session's memory.

      What would I do to the script below so that it does this.

      I understand why the below script doesn't work but I don't know how to fix it.

       

      Regards

       

      Trevor

       

      #target indesign
      #targetengine Trevor
      var w = Window.find ("palette", "My Palette")
      if (w) w.show()
      else 
      {
          alert("new window");
          var w = new Window ("palette", "My Palette", [50,50,300,300]);
          var e = w.add('edittext',[50,50,200,200])
          }
      w.onClose = function (){w.remove(e); w = null}; 
      w.show();
      
        • 1. Re: Deleting a palette form a Session Targetengine
          Dirk Becker Level 4

          Instead of assigning null you may try the delete operator. Don't delete object slots though if they are defined with prototypes, at least in older versions of ExtendScript that would remove them from the prototype.

           

          The gc() function of the helper object "$" then invokes the ExtendScript garbage collection. Sometimes multiple passes work more thorough, I usually call it twice.

           

          If your object is still not purged, you can narrow down the culprit by using $.summary(). There might be remaining references from any of the mentioned objects, e.g. closures (called workspace in that list) and member variables of function objects were causing trouble the last time I tried.

           

          delete w;

          $.gc();

          $.gc();

          • 2. Re: Deleting a palette form a Session Targetengine
            Trevorׅ Adobe Community Professional

            Hi Dirk

             

            As far as I can gather there are 2 problems with using delete here.

             

            1) deleting declared variables is a problem see the link here that Marc gives here http://forums.adobe.com/message/3274984#3274984

             

            2) because the delete is in the onClose and the onClose is triggered when the window is open i.e. before close then the delete is always going to return false. At most it could delete the variable but not the actual Window.

             

            setting to null and then calling $.gc() will likewise fail because it's only going to destroy the variable but not the actual Window.

             

            I shall look over that link above more carefully.  I think the key could lie there.

             

            I don't understand how to use the $.summary() to locate the trouble, the summary given is very vague, how should I use it?

             

            Trevor

            • 3. Re: Deleting a palette form a Session Targetengine
              Dirk Becker Level 4

              Hmm, that's an old thread. Tino had learned the hard way that in some special situations ExtendScript leaks objects, finally taking down the whole InDesign Server when the memory was exhausted. For the worse, at that time a restart took prohibitively long, due to other bugs.

               

              Most of the leaks in that project were indeed due to extensive use of closures. We've since then replaced most of the closures with prototype objects and what Harbs called Helper objects, resulting in big performance gains. Parts of the code are now again used in permanent target engines.

               

              There are other situations that also cause leaks - I already mentioned member variables of function objects in this thread, and circular references in prototypes in the old thread. I think tests with newer versions instead of CS4 also showed improvements (I had filed several bug reports), but it's been a while.

               

              In order to find leaks you run $.summary() twice - once before the actual script execution and once when done. Of course you should also run a double $.gc() before each $.summary(). You then output only the differences of the summary, in order to hide the objects that are allocated only once. If you track $.summary() differences in every test run from the beginning of a project, you'll easily identify the individual change that introduced a new object.

               

              In my tests for scripts $.summary() has proven more useful than watching the total memory used by the InDesign process, or other diagnostics, because InDesign will also build up internal caches that are only released in low memory situations.

               

              Even though the majority of my scripting has been on InDesign Server, ExtendScript should also purge the window object as soon it becomes unreachable, especially with the help of an explicit $.gc(). On the other hand I would not depend on that for a palette window at all, instead I'd just hide and show/reuse the palette as required.

               

              On the use of delete - Marc is right for global variables, I usually store the window object and related functions within one single object which itself is stored in the global variable. This way the global namespace is less cluttered, resulting in more speed improvements, and delete will work on the slots of that object.

               

              Dirk

              2 people found this helpful
              • 4. Re: Deleting a palette form a Session Targetengine
                Marc Autret Level 4

                Hi Trevor, Dirk,

                 

                I never found a definitive way to properly release from memory a complex window. As Dirk said $.gc() may help, but depending on the version of ScriptUI some precautions are necessary to prevent ID from crashing. What is sure is that you need to carefully nullify references, remove some event listeners at the right time, deal with closures if used, and so on. But even with much effort there are still tricky memory leaks, for example with ScriptUIBrush objects—not to mention very obscure issues when dealing with win.layout object.

                 

                Anyway, when you have a palette in a persistent engine (and provided that you want it to behave as a singleton), I don't see the reason why you want to actually kill the reference in memory. Just set and manage that instance in a compact location, and make sure you never needlessly rebuild your stuff.

                 

                What is the problem with the following code?

                 

                #targetengine ManageSingletonPalette
                
                $.UserInterface || ($.UserInterface = function F(/*-1=destroy 0=restore 1=rebuild*/FLAG)
                //--------------------------------------
                {
                    F.W || (F.W=Window.find("palette", "My Palette"));
                
                    // Destroy?
                    // ---
                    if( F.W && FLAG )
                        {
                        F.W.visible && F.W.close();
                        F.W = null;
                        delete F.W;
                        }
                
                    if( -1===FLAG ) return;
                
                    // Create?
                    // ---
                    if( !F.W )
                        {
                        F.W = new Window('palette', "My Palette", [50,50,300,300], {resizeable:true});
                        F.W.add('edittext',[50,50,200,200]);
                        // etc.
                        }
                
                    F.W.visible || F.W.show();
                });
                
                $.UserInterface(); // use -1 to KILL the palette, 1 to REBUILD it from scratch
                

                 

                @+

                Marc

                • 5. Re: Deleting a palette form a Session Targetengine
                  Trevorׅ Adobe Community Professional

                  Hi Dirk and Marc

                   

                  Thank you both very much for your responces.

                   

                  Marc, your method does seem to destroy the Window if called after the palette is closed.

                  The question now is how does one trigger that $.UserInterface(-1) should be call after the Window is closed?

                  Would the best way of doing this be to use an onClose to create an idleTask that will call the $.UserInterface(-1) function and then remove itself?

                   

                  Trevor

                  • 6. Re: Deleting a palette form a Session Targetengine
                    Marc Autret Level 4

                    Hi Trevor,

                     

                    The question is why and/or when the palette should be destroyed, depending on how your app interacts with it. Maybe I missed something, but I was assuming that the palette provides a persistent UI. Its state then basically depends on what the user does (including the event that he closes the window). Using a persistent container, $.UserInterface, offers you in addition the option to safely and programatically close the window when some condition is reached.

                     

                    Anyway I still don't see why you would need to have an onClose handler in that case. If your purpose is only to free up memory in your engine when the user closes the palette, this is not that critical. As long as your code handles at most a single instance of the object and does not introduce memory leaks—as guaranteed by $.UserInterface—there is not serious risk in this matter.

                     

                    Note that my sample code does not use closures, that is, ExtendScript workspaces, so there is no residual reference to the palette once we have successively done:

                     

                    F.W.close();

                    F.W = null;

                    delete F.W;

                     

                    From that point the automatic garbage collection should work the regular way—and $.summary() should never report more than one Window reference. Am I wrong?

                     

                    @+

                    Marc

                    1 person found this helpful
                    • 7. Re: Deleting a palette form a Session Targetengine
                      Trevorׅ Adobe Community Professional

                      Hi Marc,

                       

                      I have spent some time testing the script.

                      I made some changes for the purpose see below.

                       

                      Now ignoring the CC crash problem which I shall place later today on http://forums.adobe.com/message/5480694#5480694 (Thanks a million for your brilliant script there! works excellently), by pressing on the "CRASH CC / Destroy On CS" ON CS it looked like that when $.UserInterface(-1) is called from within its own palette it destroys itself but not quite to the same extent as calling $.UserInterface(-1) from outside its own palette (Click the "Destroy" Button).  It seemed to be an extra function and an extra work space. This seemed to be the case even on clicking the "Completely Obliterate??" button BUT by clicking on the "Hide" button one can see the the script actually works beautifully. (except for the CC crash issue - any solution to that? [don't spend more than 5 minutes on it])

                       

                      Either way as you in different words pointed out that we are not using Spectrum ZX81 or Comidor 64 computers any more so we shall survive.

                       

                      Thanks again

                       

                      Trevor

                       

                      // Function by Marc Autret with Control Panel and Crash button added by Trevor :-)
                      #targetengine ManageSingletonPalette
                      $.UserInterface || ($.UserInterface = function F(/*-1=destroy 0=restore 1=rebuild*/FLAG)
                      //--------------------------------------
                      {
                          F.W || (F.W=Window.find("palette", "My Palette"));
                      
                          // Destroy?
                          // ---
                          if( F.W && FLAG )
                              {
                              F.W.visible && F.W.close();
                              F.W = null;
                              delete F.W;
                              }
                      
                          if( -1===FLAG ) return;
                      
                          // Create?
                          // ---
                          if( !F.W )
                              {
                              F.W = new Window('palette', "My Palette",[100,100,350,410]);
                              myEditText = F.W.add('edittext', [10,50,240,240], "Random Number: " + Math.random()+ "\rObserve changes in the Random Number\r\rWARNING!!!!\r\rCLICK THE  ABOVE BUTTON\rTO CRASH CC\r\rYOU HAVE BEEN WARNED!!!\r\rSAFE TO USE ON CS R.I.P.", {multiline: true});  
                              crashCloseButton =  F.W.add('button', [10,10,240,40],"CRASH CC / Destroy On CS");  // By Trevor
                              completelyObliterateButton =  F.W.add('button', [10,250,240,300],"Completely Obliterate??");  // By Trevor
                              crashCloseButton.onClick = function () {$.UserInterface(-1); summarize (); /* $.UserInterface(-1) call here causes the crash */ }; // By Trevor THIS IS THE CRASH LINE ON CC
                              completelyObliterateButton.onClick = function () {$.UserInterface(-1); $.UserInterface = null; delete $.UserInterface; $.gc(); summarize (); }; // The same summary is given here as given by the "CRASH CC / Destroy On CS" button
                              }
                      
                          F.W.visible || F.W.show();
                      });
                      
                      
                      // From here by Trevor
                      w = new Window('palette', "My Control Palette",[400,100,800,500]);
                      b1 = w.add('button', [10,10,240,50],"Show");  
                      b2 = w.add('button', [10,60,240,100],"Hide");  
                      b3 = w.add('button', [10,110,240,150],"Destroy");  
                      b4 = w.add('button', [10,160,240,200],"Rebuild");  
                      b5 = w.add('button', [10,210,240,250],"Completely Obliterate!!!");  
                      b1.onClick = function () {$.UserInterface(); summarize ()};
                      b2.onClick = function () {Window.find("palette", "My Palette") && Window.find("palette", "My Palette").hide(); summarize ()};
                      b3.onClick = function () {$.UserInterface(-1); summarize ()};
                      b4.onClick = function () {$.UserInterface(1); summarize ()};
                      b5.onClick = function () {$.UserInterface(-1); $.UserInterface = null; delete $.UserInterface; $.gc(); summarize ()};
                      e = w.add('edittext', [250,10, 390, 390], "", {multiline: true});  
                      summarize ();   
                      function summarize () {e.text = "New Random Number: " + Math.random() + "\rsummary:\r" + $.summary().toString()}
                      w.show();
                       // use $.UserInterface() to show, $.UserInterface(-1) to KILL the palette, $.UserInterface(1) to REBUILD it from scratch