2

I'm trying to write an utility dealing with ffmpeg. Once i need to copy image plane from one pointer to another. From AVPicture structure to my own. Here is some sources.

My own frame structe. Memory allocated in constructor, deallocated in destructor

template <class DataType>
struct Frame
{
    DataType* data; //!< Pointer to image data
    int f_type; //!< Type of color space (ex. RGB, HSV, YUV)
    int timestamp; //!< Like ID of frame. Time of this frame in the video file
    int height; //!< Height of frame
    int width; //!< Width of frame

    Frame(int _height, int _width, int _f_type=0):
        height(_height),width(_width),f_type(_f_type)
    {
        data = new DataType[_width*_height*3];
    }

    ~Frame()
    {
        delete[] data;
    }
};

Here is the main loop performing conversion. If the line with memcpy is commented, there are no memory leaks at all. But if I uncomment it, the memory leak are present.

for(int i = begin; i < end; i++)
{
    AVPicture pict;
    avpicture_alloc(&pict, PIX_FMT_BGR24, _width, _height);
    std::shared_ptr<Frame<char>> frame(new Frame<char>(_height, _width, (int)PIX_FMT_BGR24));

    sws_scale(ctx, frame_list[i]->data, frame_list[i]->linesize, 0, frame_list[i]->height, pict.data, pict.linesize);

    memcpy(frame->data,pict.data[0],_width*_height*3);

    //temp_to_add->push_back(std::shared_ptr<Frame<char>>(frame));

    avpicture_free(&pict);
}

I've been trying lot of things such as: allocating memory via malloc and deallocating via free, copying memory from pict to frame by hands (in for loop), using std::copy and avpicture_layout that is ffmpeg helper function. Nothing helps. So the question: do I forget about something important?

I will be grateful for every answer.

Zoellick
  • 73
  • 1
  • 2
  • 8
  • What does your class do with allocated memory on copy construction and assignment?? You didn't follow the rule of 3! – πάντα ῥεῖ Oct 27 '13 at 08:15
  • Why do you think you are leaking memory? What are you using to detect the leak? Valgrind? – DanielKO Oct 27 '13 at 08:22
  • I use process explorer (Windows) and math. This is not the best way and I would appreciate any suggestions on how to find a leak. I've tried Intel Inspector, but it haven't helped me. I'm leaking memory, cause memory usage increases linearly if memcpy is uncomented. – Zoellick Oct 27 '13 at 08:36
  • Hmmm, another point: I'd guess the pixel data might be in an aligned representation, it's unlikely they're packed to exactly 24 bits. – πάντα ῥεῖ Oct 27 '13 at 08:41
  • 1
    If the code is what you posted, the contents of the `shared_ptr` will be destroyed at the end of each iteration, so a leak is not possible. The `memcpy` function doesn't perform any memory management whatsoever. – DanielKO Oct 27 '13 at 08:46
  • DanielKO: That's why I posted the question. g-makulik: Seems true. I just copied "#pragma pack(push,1)" to my source, and leaks became smaller, but they are still here. So what should I do? Is the "pragma" statement a good solution? Does it reduce perfomance? Or do I have to calcalate alignment in sources? – Zoellick Oct 27 '13 at 09:03
  • @Zoellick I meant it's unlikely that the pixel data is stored in packs of three chars rather than an array of `uint32_t` values. You may have wrong assumptions on what `AVPicture.data[0]` really is. – πάντα ῥεῖ Oct 27 '13 at 10:19
  • @g-makulik Well, got it. I've read some articles about alignment, and now some moments aren't clear for me. According to [this](http://stackoverflow.com/questions/364483/determining-the-alignment-of-c-c-structures-in-relation-to-its-members), array's data can't be aligned, but structure's members can. And AVPicture.data[0] is the pointer to the array of uint8_t. So i'm copying data from one unaligned array to another - that of course can be aligned into the structure. I can't see, where the problem is. Maybe while deallocating? Is there something i'm missing? – Zoellick Oct 27 '13 at 11:16
  • May be something goes wrong elsewhere. Your leak detection method doesn't seem to be reliable enough for me, that the problem lies in the part of the code you have shown. You should use valgrind to get better results and hints what causes your problem. – πάντα ῥεῖ Oct 27 '13 at 11:24
  • As i understand valgrind is UNIX and MacOS utility, but i'm working with Windows. Well, ok. I will try to find something else (more reliable than staring at resources usage). If there will be any results, i edit my post. Thanks. – Zoellick Oct 27 '13 at 11:32
  • Can you post code for avpicture_alloc and avpicture_free? – Arun Taylor Oct 28 '13 at 03:06
  • You can find definitions [here](http://ffmpeg.org/doxygen/trunk/group__lavc__picture.html#ga03b764a93c34d00e5a33a5ebb0b4a81b) and [here](http://ffmpeg.org/doxygen/trunk/group__lavc__picture.html#gaf4ad71a7e39b54ee70f18cc451de956f). This functions are defined in ffmpeg headers. They aren't my own. – Zoellick Oct 28 '13 at 11:52

2 Answers2

1

Are you sure that it's a leak, and not just the fact you've faulted in memory?

If you call malloc() or new, the language will give you access to the memory. The OS (in the case of a virtual memory OS such as Windows, Linux or MacOS X), however, won't actually make the pages part of your task's working set until you try to do something with that memory.

If you think you're leaking because the memcpy() caused the process size to increase in Windows' process explorer, that's a bad conclusion. Even if you free() or delete the object, the process size will not necessarily decrease.

Try these two test cases as an example. Both clearly have zero leaks.

// test 1
int main()
{
    volatile int *data = (volatile int *)malloc( (1 << 24) * sizeof(int) );
    free((void *)data);

    // Spin until killed, so we're visible in the process explorer as long as needed
    while (1)
        ;
}

and

// test 2
int main()
{
    volatile int *data = (volatile int *)malloc( (1 << 24) * sizeof(int) );
    int i;

    for (i = 0; i < (1 << 24); i++)
        data[i] = i;

    free((void *)data);

    // Spin until killed, so we're visible in the process explorer as long as needed
    while (1)
        ;
}

I suspect the second one will show a much larger memory foot print in the process explorer. It should be over 64MB.

The difference between the two programs is that the second one actually wrote to the memory it allocated, and therefore forced the OS to actually make the pages available to the task. Once the task owns the pages, it usually won't give them back to the OS.

(If it does happen to in the above example, try a smaller size such as (1 << 18) or something. Sometimes malloc does get clever here, but often it does not.)

Joe Z
  • 17,413
  • 3
  • 28
  • 39
  • Did you try to run this code yourself? I did, and you guess seems wrong. I've tryed to do it with new and malloc. The same result for both: until the memory is freed, programm has been using 64MB, but as soon as we call delete or free, it uses about 500kB. What's wrong? – Zoellick Oct 28 '13 at 17:14
  • I've done this on Linux, at least, and have seen large differences when I `malloc()` memory and use it, vs. `malloc()` it and not use it. The "Virtual Memory" size often increases, but not the "Resident Set Size." – Joe Z Nov 02 '13 at 03:26
  • @Zoellick: Ok, I ran a test on Windows XP SP3, using MinGW GCC. Just after `malloc()`, my process size does _not_ increase. On the first write to the `malloc` region, my process size jumps by the size I `malloc`. (Tested this with 64K, 1MB, 64MB.) When I `free()` the region, my process size drops again. If I `malloc()` and `free()` with no intervening write, my process size does not change. I watched process size under the Processes tab in Task Manager. – Joe Z Nov 02 '13 at 17:42
0

Your class can easily leak memory on copy construction or assignment. You should provide an explicit copy constructor and assignment operator (at least forbidden as private):

private:
    Frame(const Frame<T>& rhs);
    Frame<T>& operator=(const Frame<T>& rhs);
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • Well, thanks, get it, but nothing changes. There are no assignments and calling the copy constructor in the following code. This case something else causes leaks. But i can't understand what exactly. – Zoellick Oct 27 '13 at 08:27
  • To rephrase @DanielKO's comment then: _'Why do you think you are leaking memory?'_ – πάντα ῥεῖ Oct 27 '13 at 08:29