1

I am working on a texture synthesis project. I am almost finished, however my process is taking ~2gb of memory while it is running. I thought I was freeing all of my calloc'ed arrays, but I could be wrong. C++ isn't my specialty.

I know triple pointers were the wrong way to go about it in C++ but I am just more comfortable with them at the moment. Let me know if you need to see more code. Thank you.

MetaPic declaration

class MetaPic
{
    public:
        Pic* source;
        Pixel1*** meta;
        int x;
        int y;
        int z;
        MetaPic();
        MetaPic(Pic*);
        MetaPic(const MetaPic&);
        MetaPic(int, int, int);
        MetaPic& operator=(const MetaPic&);
        ~MetaPic();
        void allocateMetaPic();
        void copyPixelData();
        void copyToOutput(Pic*&);
        void copyToMetaOutput(MetaPic&, int, int);
        void copyToSample(MetaPic&, int, int);
        void freeMetaPic();

};

Allocating the triple pointer

    void MetaPic::allocateMetaPic()
{
    meta = (Pixel1***)calloc(x, sizeof(Pixel1**));

    for(int i = 0; i < x; i++)
    {
        meta[i] = (Pixel1**)calloc(y, sizeof(Pixel1*));
        for(int j = 0; j < y; j++)
        {
            meta[i][j] = (Pixel1*)calloc(z, sizeof(Pixel1));
        }
    }
}

Deallocating the triple pointer

void MetaPic::freeMetaPic()
{
    for(int j = 0; j < y; j++)
    {
        for(int i = 0; i < z; i++)
            free(meta[i][j]);
    }
    for(int i = 0; i < x; i++)
        free(meta[i]);

    free(meta);
}

Destructor

MetaPic::~MetaPic()
{
    freeMetaPic();
}

= Operator

MetaPic& MetaPic::operator=(const MetaPic& mp)
{
    freeMetaPic();

    source = mp.source;
    x = mp.x;
    y = mp.y;
    z = mp.z;
    allocateMetaPic();
    copyPixelData();

    return *this;
}

Copy constructor

MetaPic::MetaPic(const MetaPic& mp)
{
    source = mp.source;
    x = mp.x;
    y = mp.y;
    z = mp.z;
    allocateMetaPic();
    copyPixelData();
}
11
  • 2
    Where are the calls to alloc? Commented Dec 8, 2011 at 3:16
  • 1
    Have you tried counting how many allocs and frees you use? i.e. have an allocateCount and freeCount integer that get incremented every time you call alloc and free respectively. Then you can compare the values and see if they match. Commented Dec 8, 2011 at 3:18
  • 1
    @AlfP.Steinbach, the OP updated his question, note. Commented Dec 8, 2011 at 3:21
  • 3
    I would use STL containers instead of pointers and arrays. I also recommend new/delete instead of malloc/free, since you don't need to worry about memory sizes. The compiler handles most of the heavy lifting, making it easier on you. This may be C++, but it is not object-oriented. Commented Dec 8, 2011 at 3:22
  • 1
    Are you sure your copy constructor and assignment operator do the correct thing? Commented Dec 8, 2011 at 3:25

2 Answers 2

5

When freeing you seem to be using the wrong terminating values in your loops. Just make the freeMetaPic function undo what the allocate function does, ie:

void MetaPic::freeMetaPic()
{
    for (int i = 0; i < x; i++)
    {
        for (int j = 0; j < y; j++)
        {
            free(meta[i][j]);
        }

        free(meta[i])
    }

    free(meta);
}
Sign up to request clarification or add additional context in comments.

Comments

3

Memory freed with free() is not always returned to the OS when free()d - it may only be made available for allocation within the same process. To confirm this, run your program under a memory leak checker such as valgrind, and see if it reports any leaks when your program exits. Additionally, as Eric points out, you seem to be using the wrong terminating conditions for your deallocation loop.

If you would like to increase the chance that memory can be returned to the OS, try allocating your entire array with a single malloc or calloc call, and dividing it up into all the sub-arrays yourself - large single allocations often get special handling that (as a side effect) makes them easy to return to the OS. You could also flatten your array - that is, allocate one big mx * my * mz-element array, and access elements with e.g. z + mz * (y + my * x) (this will also be significantly faster than using multiple levels of pointers).

I would recommend just using a library that does this kind of contiguous multidimensional array allocation and lookup for you, such as the boost multidimensional array library. It's far less error-prone that way, and it's going to be much faster than doing multi-level pointer lookups.

For reference, here's how using boost multidimensional arrays might look:

class MetaPic {
  // ...
  typedef boost::multi_array<Pixel1, 3> array_type;
  typedef array_type::index index;

  array_type image;
};

void MetaPic::allocateMetaPic() {
  image.resize(boost::extents[x][y][z]);
}

void MetaPic::freeMetaPic() {
  // this is only needed to try to force the array to be freed early; you can
  // instead simply allow it to be default-destroyed when MetaPic is destroyed
  image.resize(boost::extents[1][1][1]);
}

Accessing elements in this image can be done with normal syntax (ie, image[i][j][k]). Note that it's recommended to use the index type for array indices, but you can choose to use regular ints instead if you know they'll be in range.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.