Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Memory Leak with TagData and GeDialog

    SDK Help
    0
    6
    1.0k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 11/01/2018 at 07:49, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   R19 
      Platform:      Mac OSX  ; 
      Language(s) :     C++  ;

      ---------
      Hi everyone,

      I'm using a GeDialog attached to a tag, catching MSG_EDIT to open it. So far so good.
      Everything run as i wish, but when I modify parameters on the tag itself i have memory leak.

      I've tried to isolate the problem creating an exemple as simple as possible to reproduce the problem.

      In the exemple, i've used GetDDescription() to create the UI but the problem is the same with .res/.h/.str

      This is where it get strange :
       - If i play with several parameters except the CheckBox   --> no memory leak.
       - If i play with several parameters and the CheckBox -- > memory leak.
       - If i only play with the checkbox i got no leak. (even if i got several checkbox)

      - If i remove the GeDialog variable i got no leak and using a pointer to the dialog doesn't change anything.

      I've check the way i initialise the Checkbox but even without using GeData(true) and only true it doesn't change anything.

      The main.cpp and h, there nothing except the call to registerplugin and resource.Init()

      In the exemple, the MYDIALOG class got nothing, but i didn't found anything there that could help.
      I've include everything in one file (except the main.cpp)

      I removed all other plugins to be sure.

      If anybody got a hint.

      //  memleak.cpp
      #include "c4d.h"
      // test ID
      #define PLUGIN_ID 1000002
      enum {
          
          MY_DYN_POINT_NUMBER = 1000,
        
          MY_DYN_BOOL,
          MY_DYN_BOOL_ONE,
          MY_DYN_BOOL_TWO,
          MY_DYN_SPLINE_OUTPUT,
          
          MY_DYN_REAL,
          MY_DYN_REAL_SLIDER,
          MY_DYN_ANOTHER_REAL,
          
          MY_BUTTON_ID,
        
          
          
      };
        
      class MYDIALOG : public GeDialog
      {
          
          
      };
        
        
      class MyTag : public TagData
      {
          
          INSTANCEOF(MyTag, TagData);
        
      private:
          MYDIALOG dlg;
          
      public:
          virtual     Bool				Init(GeListNode* node);
          virtual     void                Free(GeListNode* node);
          virtual     Bool				GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags);
          static      NodeData*           Alloc (void) { return NewObjClear(MyTag);}
          
      };
        
      Bool MyTag::Init(GeListNode *node)
      {
          
          node->SetParameter(MY_DYN_POINT_NUMBER, GeData(120), DESCFLAGS_SET_0);
        
          node->SetParameter(MY_DYN_BOOL, GeData(true), DESCFLAGS_SET_0);
        
          node->SetParameter(MY_DYN_SPLINE_OUTPUT, GeData(CUSTOMDATATYPE_SPLINE, DEFAULTVALUE), DESCFLAGS_SET_0);
          
          node->SetParameter(MY_DYN_REAL, GeData(1.0), DESCFLAGS_SET_0);
          node->SetParameter(MY_DYN_ANOTHER_REAL, GeData(5.0), DESCFLAGS_SET_0);
          node->SetParameter(MY_DYN_REAL_SLIDER, GeData(500.0), DESCFLAGS_SET_0);
          
      //    dlg = NewObjClear(MYDIALOG);
          
          return true;
      }
        
      void MyTag::Free(GeListNode *node)
      {
      //    DeleteObj(dlg);
        
      }
        
        
      Bool MyTag::GetDDescription(GeListNode *node, Description *description, DESCFLAGS_DESC &flags)
      {
          
          if (!description->LoadDescription(Tbase))
              return false;
          
          
          const DescID* singleid = description->GetSingleDescID();
          DescID cid;
         
          
          
        
          
          // point number ------------------------------------------------------
          
          cid = DescLevel(MY_DYN_POINT_NUMBER, DTYPE_LONG,0);
          if (!singleid || cid.IsPartOf(*singleid, nullptr))
          {
              BaseContainer bc = GetCustomDataTypeDefault(DTYPE_LONG);
              bc.SetString(DESC_NAME, "Dyn point number");
              bc.SetInt32(DESC_SCALEH, 1);
              bc.SetInt32(DESC_MIN, 0);
              bc.SetInt32(DESC_MAX, 1000);
              bc.SetInt32(DESC_STEP, 1);
              description->SetParameter(cid, bc, DescLevel(ID_TAGPROPERTIES));
          }
          // bool  ------------------------------------------------------
          cid = DescLevel(MY_DYN_BOOL, DTYPE_BOOL, 0);
          if (!singleid || cid.IsPartOf(*singleid, nullptr))
          {
              BaseContainer bc = GetCustomDataTypeDefault(DTYPE_BOOL);
              bc.SetString(DESC_NAME, "dyn bool");
              description->SetParameter(cid, bc, DescLevel(ID_TAGPROPERTIES));
          }
            // spline  ------------------------------------------------------
          cid = DescLevel(MY_DYN_SPLINE_OUTPUT, CUSTOMDATATYPE_SPLINE, 0);
          
          if (!singleid || cid.IsPartOf(*singleid, nullptr))
          {
              BaseContainer bc = GetCustomDataTypeDefault(CUSTOMDATATYPE_SPLINE);
              
              bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_SPLINE);
              bc.SetString(DESC_NAME, "dyn weight");
              bc.SetBool(SPLINECONTROL_GRID_H, true);
              bc.SetBool(SPLINECONTROL_GRID_V, true);
              bc.SetBool(SPLINECONTROL_VALUE_EDIT_H, true);
              bc.SetBool(SPLINECONTROL_VALUE_EDIT_V, true);
              bc.SetFloat(SPLINECONTROL_X_MIN, 0);
              bc.SetFloat(SPLINECONTROL_X_MAX, 1);
              bc.SetFloat(SPLINECONTROL_Y_MIN, 0);
              bc.SetFloat(SPLINECONTROL_Y_MAX, 1);
              
              
              description->SetParameter(cid, bc, DescLevel(ID_TAGPROPERTIES));
          }
          
          // real ------------------------------------------------------
          
          cid = DescLevel(MY_DYN_REAL, DTYPE_REAL, 0);
          
          if (!singleid || cid.IsPartOf(*singleid, nullptr))
          {
              BaseContainer bc = GetCustomDataTypeDefault(DTYPE_REAL);
              
              bc.SetString(DESC_NAME, "dyn Real");
              bc.SetInt32(DESC_SCALEH, 1);
              bc.SetInt32(DESC_MIN, 0);
              bc.SetInt32(DESC_MAX, 1000);
              bc.SetInt32(DESC_STEP, 1);
              bc.SetInt32(DESC_UNIT, DESC_UNIT_METER);
              
              description->SetParameter(cid, bc, DescLevel(ID_TAGPROPERTIES));
          }
          
          
          
          // another real ------------------------------------------------------
          cid = DescLevel(MY_DYN_ANOTHER_REAL, DTYPE_REAL, 0);
          
          if (!singleid || cid.IsPartOf(*singleid, nullptr))
          {
              BaseContainer bc = GetCustomDataTypeDefault(DTYPE_REAL);
              
              bc.SetString(DESC_NAME, "dyn another Real");
              bc.SetInt32(DESC_SCALEH, 1);
              bc.SetInt32(DESC_MIN, 0);
              bc.SetInt32(DESC_MAX, 10);
              bc.SetFloat(DESC_STEP, 0.1);
              
              description->SetParameter(cid, bc, DescLevel(ID_TAGPROPERTIES));
          }
          
          
          
          // real slider  ------------------------------------------------------
          
          cid = DescLevel(MY_DYN_REAL_SLIDER, DTYPE_REAL, 0);
          
          if (!singleid || cid.IsPartOf(*singleid, nullptr))
          {
              BaseContainer bc = GetCustomDataTypeDefault(DTYPE_REAL);
              
              bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_REALSLIDER);
              bc.SetString(DESC_NAME, "dyn Real Slider");
              bc.SetInt32(DESC_SCALEH, 1);
              bc.SetInt32(DESC_MIN, 0);
              bc.SetInt32(DESC_MAX, 1000);
              bc.SetInt32(DESC_STEP, 1);
              bc.SetInt32(DESC_UNIT, DESC_UNIT_METER);
              
              // slider settings
              bc.SetFloat(DESC_MINSLIDER, 250);
              bc.SetFloat(DESC_MAXSLIDER, 750);
              
              description->SetParameter(cid, bc, DescLevel(ID_TAGPROPERTIES));
          }
        
          // Button ------------------------------------------------------
          
           cid = DescLevel(MY_BUTTON_ID, DTYPE_BUTTON,0);
          
          if (!singleid || cid.IsPartOf(*singleid, nullptr))
          {
              BaseContainer bc = GetCustomDataTypeDefault(DTYPE_BUTTON);
              bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON); // done with default data type ?
              bc.SetString(DESC_NAME, "Push me");
              bc.SetInt32(DESC_ANIMATE, DESC_ANIMATE_OFF);
              bc.SetBool(DESC_SCALEH, true);
              description->SetParameter(cid, bc, DescLevel(ID_TAGPROPERTIES));
          }
          
        
          
          flags |= DESCFLAGS_DESC_LOADED;
          
          
          return SUPER::GetDDescription(node, description, flags);
      }
        
        
        
        
        
      Bool RegisterMemLeakTest(void);
        
      Bool RegisterMemLeakTest()
      {
          
          return RegisterTagPlugin(PLUGIN_ID, "testing Leak", TAG_EXPRESSION | TAG_VISIBLE   , MyTag::Alloc, "", nullptr, 0);
      }
        
      

      and the memory leaks (the first one is always there)

      Memory Leaks Detected:
      ../../../frameworks/core.framework/source/maxon/basearray.h (223) : Memory leak of 16 bytes () at 0x114abb500
      /perforce_buildsystem_osx/compile-osx-3-release/depot/release/19.0/modules/c4dplugin/source/src/richard/genesis/ge_smart_link.cpp (465) : 2 Memory leaks of 40 bytes (, first leak at 0x13376c800)
      /perforce_buildsystem_osx/compile-osx-3-release/depot/release/19.0/modules/c4dplugin/source/src/richard/genesis/ge_smart_link.cpp (584) : 2 Memory leaks of 72 bytes (, first leak at 0x108d61580)
      /perforce_buildsystem_osx/compile-osx-3-release/depot/release/19.0/modules/c4dplugin/source/src/tilo/cgui/cgui_coffeedialog.cpp (1421) : 2 Memory leaks of 624 bytes (, first leak at 0x136e2ec00)
      /perforce_buildsystem_osx/compile-osx-3-release/depot/release/19.0/modules/c4dplugin/source/src/tilo/cgui/cgui_coffeedialog.cpp (1432) : 2 Memory leaks of 400 bytes (, first leak at 0x134569300)
      /perforce_buildsystem_osx/compile-osx-3-release/depot/release/19.0/modules/c4dplugin/source/src/tilo/cgui/cgui_coffeedialog.cpp (2968) : 2 Memory leaks of 1368 bytes (, first leak at 0x12e82f700)
      /perforce_buildsystem_osx/compile-osx-3-release/depot/release/19.0/modules/c4dplugin/source/src/tilo/cgui/cgui_main.cpp (114) : 2 Memory leaks of 600 bytes (, first leak at 0x136e2ef00)
      /perforce_buildsystem_osx/compile-osx-3-release/depot/release/19.0/modules/c4dplugin/source/src/tilo/cgui/cgui_main.cpp (157) : 2 Memory leaks of 488 bytes (, first leak at 0x134712280)
      8 blocks not freed
      
      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 12/01/2018 at 03:50, xxxxxxxx wrote:

        Hi,

        A NodeData plugin can't hold a GeDialog like a CommandData.
        An object plugin is created multiple times (on the undo stack for instance) and is also managed in different threads than the main. Remember GUI operations have to be done in the main threads.

        The solution is to have a CommandData holding the dialog. Then from the tag's MSG_EDIT use CallCommand() to invoke it.
        MSG_EDIT is run on the main thread so GUI operations can be done. Same for MSG_DESCRIPTION_COMMAND with buttons in descriptions.

        Catch EVMSG_CHANGE from the dialog's CoreMessage() to refresh it according to the tag's state.

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 12/01/2018 at 08:36, xxxxxxxx wrote:

          Ok changing all this.

          i'm storing data in the tag (not in a basecontainer)
          Using SpecialEventAdd() to send a pointer to my data after the callCommand seems to work. Is it ok to do that ?

          edit : 
          even with those change i still got memory leak when i'm playing with checkbox

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 12/01/2018 at 09:06, xxxxxxxx wrote:

            Originally posted by xxxxxxxx

            Using SpecialEventAdd() to send a pointer to my data after the callCommand seems to work. Is it ok to do that ?

            Yes that's fine.

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 16/01/2018 at 00:46, xxxxxxxx wrote:

              after changing the data stored in the tag, i've killed the memory leak. Thanks for the support 🙂

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 16/01/2018 at 01:35, xxxxxxxx wrote:

                You're welcome. Glad the memory leak is solved.

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post