D
D
devalone2017-06-26 00:33:07
C++ / C#
devalone, 2017-06-26 00:33:07

Where is the memory leaking?

There is a Worker class:

class Worker : public AbstractWorker {
public:
    Worker(Core* core, Module* module, WORKER_TYPE type = WORKER_TYPE::BEFORE_GRAPHICS, bool synchronized = false, const std::string& name = "");
    Worker(std::function<void(Worker*, unsigned)> function, Core* core, Module* module, WORKER_TYPE type = WORKER_TYPE::BEFORE_GRAPHICS, bool synchronized = false, const std::string& name = "");
    virtual ~Worker();

    virtual void handle(unsigned microseconds);

    WORKER_TYPE getType() const;

    bool isSynchronized() const;

protected:
    const WORKER_TYPE type;
    const bool synchronized;

private:
    std::function<void(Worker*, unsigned)> function;
};

The important thing here is , which is passed in the constructor and called from handlestd::function<void(Worker*, unsigned)> function;
void Worker::handle(unsigned microseconds)
{
    if (function)
        function(this, microseconds);
}

The handle function itself is called from Core in a loop like this:
while (_isAlive) {
        // TODO: убрать расход ресурсов на выделение памяти и прочее
        // parallel processing
        std::vector<std::future<void>> tasks;
        for (auto& worker : beforeGraphicsWorkers) {
            beforeGraphicsWorkersThreadPool->enqueue(
                [this, worker] {
                    auto now = getTimePoint();
                    auto dt = std::chrono::duration_cast<std::chrono::microseconds>(now - worker->previousHandlingTime).count();
                    worker->handle(dt);
                    worker->previousHandlingTime = now;
                });
        }

        // wait for threads finishing
        for (auto& task : tasks)
            task.wait();

// остальный код

    }

If you just add a lambda that will do something, then everything is ok, for example like this:
core.registerWorker(std::make_shared<Worker>([&core](auto worker, unsigned microseconds) {
        static int i = 0;
        i++;
    }, &core, nullptr));

registerWorker adds a Worker to a vector that is iterated over in the processing function above. But if you add output to the Worker, then the memory quickly goes into oblivion, for example like this:
core.registerWorker(std::make_shared<Worker>([&core](auto worker, unsigned microseconds) {
        static int i = 0;
        i++;
        std::cout << i << std::endl;
    }, &core, nullptr));

If you inherit from Worker and do not use lambdas, the same thing.
What's the magic? Maybe this has something to do with the fact that Workers are constantly called from different threads?
Valgrind says that's the way it should be -_-
==5048==
==5048== HEAP SUMMARY:
==5048== in use at exit: 0 bytes in 0 blocks
==5048== total heap usage: 1,851,012 allocs, 1,851,012 frees, 85,222,489 bytes allocated
==5048= ===5048 ==
All heap blocks were freed -- no leaks are possible
==5048==
==5048== For counts of detected and suppressed errors, rerun with: -v
==5048== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Answer the question

In order to leave comments, you need to log in

1 answer(s)
K
Konstantin Stepanov, 2017-06-26
@koronabora

IMHO:
1) The working version is degenerated by the compiler into doing nothing
static int i = 0;
i++;
2) Real actions spawn a lot of variables on the heap, so the memory is captured. This is not a leak.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question