Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to free memory from a list of images?
Forum Updated to NodeBB v4.3 + New Features

How to free memory from a list of images?

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 4 Posters 3.5k Views 3 Watching
  • 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.
  • mrjjM Offline
    mrjjM Offline
    mrjj
    Lifetime Qt Champion
    wrote on last edited by mrjj
    #2

    Hi
    Dont you delete your old instance? (PhotoHandler)
    It should then delete the photoList and it will free the QImages?

    X kshegunovK 2 Replies Last reply
    0
    • mrjjM mrjj

      Hi
      Dont you delete your old instance? (PhotoHandler)
      It should then delete the photoList and it will free the QImages?

      X Offline
      X Offline
      xtingray
      wrote on last edited by
      #3

      @mrjj Yes, I manually delete the PhotoHandler instance. In some point of my application I do:

      PhotoHandler *handler = new PhotoHandler();
      

      And then when the object life-cycle is done, I do:

      delete handler;
      

      I was expecting that this action would free some memory, but it doesn't happen. Am I doing it wrong?


      Qt Developer

      1 Reply Last reply
      0
      • mrjjM mrjj

        Hi
        Dont you delete your old instance? (PhotoHandler)
        It should then delete the photoList and it will free the QImages?

        kshegunovK Offline
        kshegunovK Offline
        kshegunov
        Moderators
        wrote on last edited by kshegunov
        #4

        @xtingray

        Hello,
        Your description is great but some more code will be useful.

        I understand this behaviour, I mean, every new class instance requires a new segment of memory so the memory consumption most be incremented, but how can I free the memory used by the previous instance of the same class that was already destroyed? What is the right procedure to release the used memory in my case?

        This a very vague question to which the answer would be: deleting the object, however I have the feeling you're not after that exact answer.
        On a related note, the containers QList, QVector and the image classes Qimage, QPixmap use implicit sharing, so they share the memory (until a write operation is required, when they detach the data). The allocated memory itself will be freed when the last instance of the class is destroyed.

        Is your PhotoHandler class being derived from QObject? Do you delete the instances? Is it holding references to anything else beside the list of images?

        Kind regards.

        EDIT:
        When you do this:

        PhotoHandler *handler = new PhotoHandler();
        

        are you storing the returned pointer?

        When you do this:

        delete handler;
        

        is handler NULL or is it pointing to a memory location?

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        1
        • ? Offline
          ? Offline
          A Former User
          wrote on last edited by
          #5

          Hi!
          If you want to find memory leaks use valgrind, not top. If you want to prevent memory leaks use smart pointers (e.g. QSharedPointer). "Why doesn't delete / free return memory to the operating system?" This question is up to the developers of your C library. The usual answer is "because it would be stupid (inefficient) to do so as long as the system still has unused physical RAM". If you really want to force the C library to give the freed memory of your process back to the system then malloc_trim(0) should do the trick.
          Cheers!

          kshegunovK 1 Reply Last reply
          0
          • ? A Former User

            Hi!
            If you want to find memory leaks use valgrind, not top. If you want to prevent memory leaks use smart pointers (e.g. QSharedPointer). "Why doesn't delete / free return memory to the operating system?" This question is up to the developers of your C library. The usual answer is "because it would be stupid (inefficient) to do so as long as the system still has unused physical RAM". If you really want to force the C library to give the freed memory of your process back to the system then malloc_trim(0) should do the trick.
            Cheers!

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by kshegunov
            #6

            @xtingray

            @Wieland said:

            The usual answer is "because it would be stupid (inefficient) to do so as long as the system still has unused physical RAM". If you really want to force the C library to give the freed memory of your process back to the system then malloc_trim(0) should do the trick.

            It's a bit more convoluted that that. delete does release the memory back to the heap manager (which is part of the OS) and whether or not it's viewed as "free" in top/Task manager depends on the actual implementation. When you new an object, the C runtime requests that a piece of memory is allocated for your use, but it's pretty much oblivious (from the user standpoint) how the memory is managed at the OS level. Linux usually caches almost all the available physical memory and distributes it as it sees fit. This is also needed since the OS might want to do paging or swapping of some rarely used memory segments (it is the default behavior).

            For example on my machine the 16GB physical memory (I'm not using swap) is almost all belonging to the kernel (top reports a mere 300MB free). Nonetheless, that memory is still available to different processes whenever they need it. The heap manager on Windows is a bit different but in principle it has the same purpose - to manage the heap.

            You can think of the heap as a big jumble of used and unused memory blocks (whence the name), while the stack is a nice orderly stack of books (whence the name yet again). So the heap usually has a lot of holes (unused memory) lying around, often referred as heap fragmentation, especially if the heap manager is not very good. When you request a piece of memory for use, the manager will find you a calm cosy place to give you where you can put your variables. However, it also may decide to shuffle things around if it's needed. So for example realloc might actually cause a change of address (because data was moved to another place where there's enough space for the new memory block).

            In conclusion, top is not a good tool to trace memory usage (as Wieland pointed out). Although, I don't see how malloc_trim will do you any good in this case.

            Kind regards.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            0
            • X Offline
              X Offline
              xtingray
              wrote on last edited by
              #7

              I want to thank you all for your comments and suggestions. I hope this thread could be helpful for other newbies in the future.

              I had heard about Valgrind barely in the past, but I never tried it until now. I wonder that I could get some kind of warnings even about several Qt and VirtualBox libraries. I will have to read more to understand all the output this tool is giving to me. Here is the leak summary of my first test running my program for several minutes:
              ==7582== LEAK SUMMARY:
              ==7582== definitely lost: 31,305 bytes in 297 blocks
              ==7582== indirectly lost: 42,600,715 bytes in 10,065 blocks
              ==7582== possibly lost: 389,850,894 bytes in 282 blocks
              ==7582== still reachable: 2,242,342 bytes in 20,196 blocks
              ==7582== suppressed: 0 bytes in 0 blocks

              Now, I will try to describe my application briefly using some lines of code. My main class inherits from the QTabWidget class:

              class MyMainWindow : public QTabWidget
              

              As part of my global variables for this class, I have:

              PhotoHandler *handler;
              

              In the section of the GUI definition, I have two QPushButton objects which trigger the SLOTS where variable handler is created and deleted:

              QPushButton *startButton = new QPushButton("Start session",  this);
              connect(startButton, SIGNAL(clicked()), this, SLOT(startSession()));
              QPushButton *stopButton = new QPushButton("Stop session",  this);
              connect(stopButton, SIGNAL(clicked()), this, SLOT(stopSession()));
              

              So, in the SLOTS definition I got something like:

              void MyMainWindow ::startSession() 
              {
                  handler = new PhotoHandler();
                  handler->someHandyProcedure();
                  ...
              }
              void MyMainWindow ::stopSession()
              {
                  handler->stopSomeActions();
                  delete handler;
              }
              

              I just would like to know if this small example follows the basics about memory management (I am aware my problem will require many Valgrind sessions and a lot of reading)


              Qt Developer

              kshegunovK 1 Reply Last reply
              0
              • X xtingray

                I want to thank you all for your comments and suggestions. I hope this thread could be helpful for other newbies in the future.

                I had heard about Valgrind barely in the past, but I never tried it until now. I wonder that I could get some kind of warnings even about several Qt and VirtualBox libraries. I will have to read more to understand all the output this tool is giving to me. Here is the leak summary of my first test running my program for several minutes:
                ==7582== LEAK SUMMARY:
                ==7582== definitely lost: 31,305 bytes in 297 blocks
                ==7582== indirectly lost: 42,600,715 bytes in 10,065 blocks
                ==7582== possibly lost: 389,850,894 bytes in 282 blocks
                ==7582== still reachable: 2,242,342 bytes in 20,196 blocks
                ==7582== suppressed: 0 bytes in 0 blocks

                Now, I will try to describe my application briefly using some lines of code. My main class inherits from the QTabWidget class:

                class MyMainWindow : public QTabWidget
                

                As part of my global variables for this class, I have:

                PhotoHandler *handler;
                

                In the section of the GUI definition, I have two QPushButton objects which trigger the SLOTS where variable handler is created and deleted:

                QPushButton *startButton = new QPushButton("Start session",  this);
                connect(startButton, SIGNAL(clicked()), this, SLOT(startSession()));
                QPushButton *stopButton = new QPushButton("Stop session",  this);
                connect(stopButton, SIGNAL(clicked()), this, SLOT(stopSession()));
                

                So, in the SLOTS definition I got something like:

                void MyMainWindow ::startSession() 
                {
                    handler = new PhotoHandler();
                    handler->someHandyProcedure();
                    ...
                }
                void MyMainWindow ::stopSession()
                {
                    handler->stopSomeActions();
                    delete handler;
                }
                

                I just would like to know if this small example follows the basics about memory management (I am aware my problem will require many Valgrind sessions and a lot of reading)

                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by
                #8

                @xtingray

                Hello,
                I'd suggest setting the pointer to NULL after deletion and handling the case where two consecutive starts may be encountered. Another option is to add internal states to the handler object and use auto storage (stack variables) instead of doing everything in the heap. For example, I'd do something like:

                MyMainWindow::MyMainWindow(QWidget * parent)
                    : QTabWidget(parent), handler(NULL)
                {
                }
                
                MyMainWindow::~MyMainWindow()
                {
                    stopSession();
                }
                
                void MyMainWindow::startSession() 
                {
                    stopSession();
                
                    handler = new PhotoHandler();
                    handler->someHandyProcedure();
                    
                    // ...
                }
                
                void MyMainWindow::stopSession()
                {
                    if (!handler)
                         return;
                
                    handler->stopSomeActions();
                
                    delete handler;
                    handler = NULL;
                }
                

                You could also consider one of the pointer-wrapper classes. QScopedPointer would seem appropriate in this case. Something along the lines of:

                class MyMainWindow : public QTabWidget
                {
                    Q_OBJECT
                
                private:
                    QScopedPointer<PhotoHandler> handler;
                };
                
                void MyMainWindow::startSession() 
                {
                    stopSession();
                
                    handler.reset(new PhotoHandler());
                    handler->someHandyProcedure();
                    // ...
                }
                
                void MyMainWindow::stopSession()
                {
                    if (handler.isNull())
                        return;
                 
                   handler->stopSomeActions();
                   handler.reset();
                }
                

                I'm a stack aficionado, so I'd actually implement it similarly to:

                
                class MyMainWindow : public QTabWidget
                {
                    Q_OBJECT
                
                private:
                    PhotoHandler handler;
                };
                
                void MyMainWindow::startSession() 
                {
                    if (handler.started())
                        return; //< Or .stop() depending on the case
                
                    handler.someHandyProcedure();
                    // ...
                }
                
                void MyMainWindow::stopSession()
                {
                   handler.stop();
                }
                

                and ultimately not bother about the cleanup.
                I hope that helps.

                Kind regards.

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                0
                • ? Offline
                  ? Offline
                  A Former User
                  wrote on last edited by
                  #9

                  Your memory management looks perfectly ok to me. But as soon as thinks become more complex (more code paths) you'll have to think harder and harder when it's necessary to delete your manually managed objects (here this is only handler) and you'll find yourself in the situation that you'll add more and more delete's. This is when smart pointers come into play. You could for example do it like this:

                  QSharedPointer<PhotoHandler> sp_handler;
                  
                  void MyMainWindow::startSession()
                  {
                      sp_handler.reset( new PhotoHandler() );
                      sp_handler->someHandyProcedure();
                  }
                  
                  void MyMainWindow::stopSession()
                  {
                      sp_handler->stopSomeActions();
                  }
                  

                  Now your handler object get's deleted automatically as soon as it's no longer used.

                  1 Reply Last reply
                  0
                  • X Offline
                    X Offline
                    xtingray
                    wrote on last edited by
                    #10

                    @kshegunov @Wieland I'm going to try the approaches you have proposed to find out which fits better for my needs. Just one last question to finish this thread:

                    • What means the memory information I get from the "top" command in Unix? Does it represents the "mapped" memory of the process, but not necessarily the currently "used"? When is useful that memory information or how should I interpret it?

                    Thanks! :)


                    Qt Developer

                    kshegunovK 1 Reply Last reply
                    0
                    • X xtingray

                      @kshegunov @Wieland I'm going to try the approaches you have proposed to find out which fits better for my needs. Just one last question to finish this thread:

                      • What means the memory information I get from the "top" command in Unix? Does it represents the "mapped" memory of the process, but not necessarily the currently "used"? When is useful that memory information or how should I interpret it?

                      Thanks! :)

                      kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by kshegunov
                      #11

                      @xtingray

                      Hi,

                      What means the memory information I get from the "top" command in Unix? Does it represents the "mapped" memory of the process, but not necessarily the currently "used"? When is useful that memory information or how should I interpret it?

                      It's an estimation, so you should interpret it as such: it gives you a coarse overview of memory and CPU time, but it's by no means exact. So, as Wieland suggested, it's a good idea to run your code through a profiler (as valgrind) and see where they might be leaks. Also adopting some of the "good practices" in programming help not having leaks in the first place. These would include but not limit themselves to:

                      • using stack-based (actually auto-storage) allocations where possible (Incidentally the stack is also much faster).
                      • using wrappers for pointers (Qt provides quite a lot, you can take a look at this thread as well)
                      • using implicit/explicit sharing
                      • enforcing RAII (each class is managing and responsible for its own resources), this'd imply not sharing resources where it's posible.

                      Kind regards.

                      Read and abide by the Qt Code of Conduct

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved