0

From last week I am trying to fix a strange memory consumption from my project. We have a logging system which has two thread, thread1 is used to collect the data and thread2 is used to parse data and write into the file. When the user want to write the data, he will inform thread1. thread1 will create the below Job class and pass the reference of Data* deque

class Job
{
    public:
    Job(std::deque<Data*> & Job)
    {
        m_dataHolder = new DataContainer();

        for (auto & pData : Job)
        {
            m_dataHolder->Add(pData->Clone());
        }
    }

    ~Job()
    {
       delete m_dataHolder;
    }

    void clear()
    {
       delete m_dataHolder;
       m_dataHolder = NULL;
    }

    void write()
    {
       if (NULL != m_dataHolder)
       {
           serialize_data();
           file_write();
       }
    }
};

here thread1 is creating a copy of Data*. Now thread1 will pass this object to thread2 and wakeup the thread using pthread_kill(). Issue is started when we have 50k records in the queue and when we create the copy memory usage goes up to 90% and it will not reduce. thread2 sample code is given below

class FileOperationsWorker()
{
    public:
    void SignalEvent(uint32_t SignalNumber)
    {
        ExecuteeMutex.lock();
        while (JobQueue.size() > 0)
        {
            Job* pNextJob = JobQueue.front();
            JobQueue.pop_front();
            ExecuteeMutex.unlock();

            pNextJob->Write();

            delete pNextJob;
            ExecuteeMutex.lock();
        }
        JobQueue.clear();
        ExecuteeMutex.unlock();
    }

    void AddJob(Job* pJob)
    {
        ExecuteeMutex.lock();
        JobQueue.push_back(pJob);
        ExecuteeMutex.unlock();
        pthread_kill(ThreadId, Signal);
    }
    std::deque<Job*> JobQueue;
};

I modified thread2 AddJob() method as below

   void AddJob(Job* pJob)
   {
        ExecuteeMutex.lock();
        JobQueue.push_back(pJob);
        pJob->clear();
        ExecuteeMutex.unlock();
        pthread_kill(ThreadId, Signal);
    }

When I cleared the pJob->clear() memory consumption reduced and came back to normal usage. But after receiving the signal I tried the same but its not reducing the memory. Another observation is next time onward file write will not increase the memory(it will stay at 90%). My question is whether STL containers will cache memory? or linux process will cache memory? There is no other code executed after giving that signal. Once the signal is received in the thread2 and even after deleting the data memory consumption is not reduced.

Shiny
  • 33
  • 1
  • 8
  • 1
    you create and kill the thread each time a new job is added ? – Arkady Godlin Apr 12 '18 at 06:34
  • 1
    I believe pthread_kill() will not kill the thread, it just give the signal to the thread – Shiny Apr 12 '18 at 06:35
  • when you create the queue with the 50k jobs, without thread 2 in play yet, what is the memory footprint for this ? – Arkady Godlin Apr 12 '18 at 06:39
  • This is just off the top of my head, but how you create `Job` instance? Because `m_dataHolder->Add(pData->Clone());` seems that you clone `Data`'s data, not pointer, so here you can create duplicate `Data` object. I assume you release original ones? – Afshin Apr 12 '18 at 06:45
  • @Afshin clear is doing the same thing and that reducing the memory usage. DataContainer is deleting its child data. – Shiny Apr 12 '18 at 06:49
  • @Shiny yes, I assume `clear()` is clearing `m_dataHolder` and its correctly correctly. But I don't know what `pData->Clone()` does. if it creates a clone of `Data` object, it means you need to delete original ones that you have passed using `deque` to the constructor I guess. – Afshin Apr 12 '18 at 07:04
  • @Afshin `Clone()` is doing `return new Data(this);` and DataContainer holding its children inside a vector and on destruction it will delete all its children – Shiny Apr 12 '18 at 07:42
  • @ArkadyGodlin before cloning 28% after cloning 90%. when i cleared the data from thread1 it came back to 28% but when I tried to clear from thread2 its stays at 90% – Shiny Apr 12 '18 at 07:47
  • Job(std::deque & Job) who delete this data objects that passed to the function ? make sure that DataContainer is getting deleted and all of it is data. it is hard to help when not all code is shown. – Arkady Godlin Apr 12 '18 at 07:53
  • @ArkadyGodlin `Job(std::deque & Job)` is passed from another class and its managed properly there. I had the same doubt initially so I kept only 1 record in the `std::deque & Job` and using a for loop I cloned 50k records and pushed into the Job. So only inside Job is having 50k records. Yes I know its difficult to understand the problem with my code. Am really sorry for that, I am trying to provide maximum informations. Please let me know if you want any other code. – Shiny Apr 12 '18 at 08:02
  • @ArkadyGodlin I already spent 2 weeks to root cause this issue. But Am not getting any idea. if I create large data from thread1 and pass to thread2 and deleted the data in thread2 why the memory usage is not coming down? This approach is not the correct way? How to know where exactly the memory is cached? – Shiny Apr 12 '18 at 08:06
  • @Shiny I don't know if it is related to your problem at all or not, but once one of my friend had problem with `deque` itself which caused him memory leaks. I don't know if my friend used `deque` incorrectly or not, but when he changed it something else, it solved his problem. I don't know if this can be cause of your problem, but if I were you, I would try passing `Data` with something rather than `deque` too. – Afshin Apr 12 '18 at 08:25
  • @Shiny please check here too https://stackoverflow.com/questions/5834754/stddeque-does-not-release-memory-until-program-exits – Afshin Apr 12 '18 at 08:27

0 Answers0