Results 1 to 8 of 8

Thread: C++ Memory Leak?

  1. #1
    Join Date
    Dec 2016
    Posts
    3
    Platforms
    Windows

    Default Re: C++ Memory Leak?

    Hey guys, so I've been working on my assignment and i'm pretty happy with it, but I've had a pretty massive problem with a memory leak (I had to limit a for loop because otherwise it was passing 2GB and just stopped running).

    I've spoken to my lecturer who will be marking this, and this was a problem he was fine helping me with (so i'm not breaching any sole work rules, don't worry), but even he had no idea where I was going wrong. I'm hoping someone here can save me (based on past experience, they will, and his name will be carnage. Much love <3).

    I'm really hoping I'm just declaring my Matrix objects incorrectly, but I thought that the way i've done it meant that it was overriding them, instead of creating more.

    So the loop that contains the memory leak(sorry this is so long):

    Qt Code:
    1. int i = 768;
    2. int j = 1024;
    3.  
    4. int startRow = 0;
    5. int endRow = 49;
    6. int startCol = 0;
    7. int endCol = 36;
    8.  
    9. Matrix SceneMatrix(i, j, input_data); //Matrix of cluttered_scene
    10. Matrix WallyMatrix(49, 36, wally_data); //Matrix of wally
    11.  
    12. Matrix BestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol); //Matrix to contain the best result that matches wally, based on a subset of SceneMatrix
    13. Matrix BestMatrix2 = BestMatrix; //Set to same details as BestMatrix(Copy constructer runs here)
    14. Matrix BestMatrix3 = BestMatrix; //Set to same details as BestMatrix(Copy constructer runs here)
    15.  
    16. if (ans == 1) { //If SSD
    17. BestMatrix.setScore(SumOfSquaredDifferences(WallyMatrix, BestMatrix));
    18. BestMatrix2.setScore(SumOfSquaredDifferences(WallyMatrix, BestMatrix2));
    19. BestMatrix3.setScore(SumOfSquaredDifferences(WallyMatrix, BestMatrix3));
    20.  
    21. }
    22.  
    23. int corrStartRow = 0; //Pos of best option
    24. int corrEndRow = 0;
    25. int corrStartCol = 0;
    26. int corrEndCol = 0;
    27.  
    28. int corrStartRow2 = 0; //Pos of second best option
    29. int corrEndRow2 = 0;
    30. int corrStartCol2 = 0;
    31. int corrEndCol2 = 0;
    32.  
    33. int corrStartRow3 = 0; //Pos of third best option
    34. int corrEndRow3 = 0;
    35. int corrStartCol3 = 0;
    36. int corrEndCol3 = 0;
    37.  
    38. double moveValue = 6; //Amount that the scanner will shift each iteration
    39.  
    40. for (endRow; endRow < (i - 49); endRow += moveValue, startRow+= moveValue) { //Loop through each row
    41.  
    42. for (endCol; endCol < (j - 36); endCol += moveValue, startCol += moveValue) { //Loop through each column
    43.  
    44.  
    45. Matrix TestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol); //Matrix that will be tested against current best matrix
    46.  
    47. if (ans == 1) { //If SSD
    48. TestMatrix.setScore(SumOfSquaredDifferences(WallyMatrix, TestMatrix)); //Test score using SSD
    49. }
    50.  
    51. if (ans == 1) { //If SSD
    52. if (TestMatrix.getScore() < BestMatrix.getScore()) { //Best option
    53.  
    54. BestMatrix = TestMatrix; //Set BestMatrix and a set of coords to the test matrix, as this is better than the previous BestMatrix
    55. corrStartRow = startRow; //Coords to be used when drawing rectangle
    56. corrEndRow = endRow;
    57. corrStartCol = startCol;
    58. corrEndCol = endCol;
    59.  
    60. }
    61.  
    62. } //end if ans == 1 (SSD)
    63.  
    64. } //End for loop of columns
    65. endCol = 36; //Move to next row
    66. startCol = 0;
    67.  
    68. } //End for loop of rows
    To copy to clipboard, switch view to plain text mode 

    And the Matrix Class:
    Qt Code:
    1. #pragma once
    2.  
    3. class Matrix { //This matrix class allows me to make a new object for each matrix I need
    4.  
    5. public: //Allows anything that is public to be accessed (e.g. matrix1.getBlock)
    6.  
    7.  
    8. Matrix(int sizeR, int sizeC, double input_data[]); //Class constructer
    9. ~Matrix(); //Class Destructer
    10. Matrix getBlock(int startRow, int endRow, int startCol, int endCol); //Function which takes a limit in terms of columns and rows, and returns the Matrix inside it
    11. double* Matrix::getMatrixVals(); //Function which returns the data array in a matrix
    12. double getScore(); //Function which returns the score variable (as it is private and cannot otherwise be accessed outside of the scope of the Matrix class)
    13. void setScore(double Score); //Function which sets the score variable
    14. int* getSceneVals(); //Function which returns the indexes that the new matrix occupied in its larger matrix (where the 36 x 49 matrix existed in terms of position inside the 1024 x 768 matrix)
    15. Matrix(const Matrix& e); //Copy Constructer
    16.  
    17.  
    18.  
    19. private: //Can't be accessed outside of Matrix class
    20. int M, N; //Amount of rows and columns in the matrix
    21. double *data; //The data read into the matrix
    22. double *newData; //The new set of data, taken out of the data variable, based on the getBlock function
    23. double score; //The score, assigned by either the Sum of Squared Differences function, or the Normalized Correlation function
    24. int* posInScene; //An array which contains the indexes that the new matrix occupied in its larger matrix (where the 36 x 49 matrix existed in terms of position inside the 1024 x 768 matrix)
    25. //To be used for putting a square around wally
    26. };
    27.  
    28. Matrix::Matrix(int sizeR, int sizeC, double input_data[]) { //The Class Constructer (runs whenever a new Matrix object is created)
    29.  
    30. M = sizeR; //M = height
    31. N = sizeC; //N = width
    32.  
    33.  
    34. data = new double[M*N]; //Sets the total space of the data array
    35. newData = new double[36*49]; //Sets the total space of the new data array
    36. posInScene = new int[36*49]; //Sets the total space of the position in scene array
    37.  
    38. for (int ii = 0; ii < M*N; ii++) { //Loops through the rows * columns of the matrix, to add the data read into the function to the data function
    39. data[ii] = input_data[ii]; //Adding each value in the data array, one by one
    40. }
    41. }
    42.  
    43.  
    44. Matrix::~Matrix() { //The class destructer, which runs every time a matrix is deleted (included when it is passed through a function as a reference)
    45.  
    46.  
    47. } //End of class destructer
    48.  
    49.  
    50.  
    51. Matrix Matrix::getBlock(int startRow, int endRow, int startCol, int endCol) { //Function which returns a Matrix based on a start/end row/column
    52.  
    53.  
    54.  
    55. int currentCol = startCol;
    56. int currentRow = startRow; //Temporary variables used to retain value of start row/start column
    57. int counter = 0;
    58.  
    59.  
    60. for (currentRow; currentRow < endRow; currentRow++) {
    61.  
    62. for (currentCol; currentCol < endCol; currentCol++) { //The nested for loop means this will run endCol * endRow times (in this case, 36 * 49 times)
    63.  
    64. newData[counter] = data[(currentRow * N) + currentCol]; //This formula will set each value of new data as the value of the matrix, as if it were a 2d matrix, using the formula (currentRow * N) + currentCol, using the values passed through the function
    65. posInScene[counter] = (currentRow * N) + currentCol; //This will store the position that each value of newData had inside data, for future reference, like when identifying wally in the cluttered_scene image
    66. counter++; //Incrementing the counter
    67. } //End of the currentCol for loop
    68. currentCol = startCol; //After finishing a row, this moves onto the next one
    69. } //End of the currentRow for loop
    70.  
    71. Matrix NewMatrix(endRow - startRow, endCol - startCol, newData); //The matrix that will be returned as the subset of the original matrix
    72.  
    73. return NewMatrix;
    74. } //End getBlock function
    75.  
    76. Matrix::Matrix(const Matrix& e) { //Copy Constructer
    77.  
    78. M = e.M;
    79. N = e.N;
    80. data = e.data;
    81. newData = e.newData;
    82. score = e.score;
    83. posInScene = e.posInScene; ///Whenever a Matrix is copied, each of these variables is set to what it was
    84. } //End copy constructer
    85.  
    86.  
    87. double* Matrix::getMatrixVals() { //Function which returns the values in the data array
    88.  
    89. double* matrixVals; //Declaring the array
    90.  
    91. int size = M * N;
    92.  
    93. matrixVals = new double[size]; ///Declares the size of the array
    94.  
    95.  
    96. for (int i = 0; i < size; i++) { //Loops through as many values as there are in the matrix
    97.  
    98. matrixVals[i] = data[i]; //Replacing every value of the array as it goes
    99. }
    100.  
    101. return matrixVals; //Returning a double array
    102. } //End of the getmatrixvals function
    To copy to clipboard, switch view to plain text mode 

    Thanks a lot,
    Danny

    *I had to remove some variables and stuff to get this post to fit, but don't worry, referencing variables that aren't here isn't the problem, it compiles perfectly*

  2. #2
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: C++ Memory Leak?

    In Matrix constructor You create 3 arrays wit operator new. You should delete them in Matrix destructor.

  3. #3
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: C++ Memory Leak?

    but even he had no idea where I was going wrong.
    He couldn't find an error this obvious? Wow. The very first thing you look for when you have a program that grows without bounds is unmatched new / delete pairs.

    By the way, as soon as you fix the memory leak, your program is likely to start crashing. You are allocating memory (via operator new()) in the Matrix constructor. You have incorrectly implemented a copy constructor and have not implemented an assignment operator for your Matrix class. The compiler will generate the assignment operator for you, but unfortunately this will make a bitwise copy of the contents of the class instance. In your case, it will copy the pointers to the arrays, not the arrays themselves. This means that as soon as the first Matrix instance goes out of scope, all of the other Matrix instances you have created via assignment or copy constructors will be left holding pointers to deleted arrays. When one of these copies tries to access the array, it will crash.

    One solution is to correctly implement a copy constructor (Matrix( const Matrix & rhs )) and assignment operator (const Matrix & operator=( const Matrix & rhs ) ). In each of these, you must create new arrays and copy the arrays held by "rhs" (right-hand side) into them. In the assignment operator, you should also protect against self assignment by checking &rhs != this first.

    The alternative solution to all this manual copying is to use std::vector< double > or std::vector< int > (or their QVector counterparts) to hold your array data. These do not need to be allocated with operator new(), do not need to be manually deleted in the destructor, and can be treated as ordinary arrays in algorithms. You will also not need to implement a copy constructor or assignment operator, since a bitwise copy of the class will make copies of the vectors and their contents too.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: C++ Memory Leak?

    I can only guess but if your lecturer didn't spot the cross mismatch between allocating memory in the constructor and not releasing it in the destructor then this is a lecture in Mathematics or Physics, not Software engineering or Computer Science, right?

    And I totally agree with d_stranz: vectors!
    No point in trying to manually get all the manual memory handling issues fixed if you can avoid them alltogether.

    Cheers,
    _

  5. #5
    Join Date
    Dec 2016
    Posts
    3
    Platforms
    Windows

    Default Re: C++ Memory Leak?

    Sorry, i didn't have space to mention, but i'd tried deleting everything in my deconstructor, but that just caused a load more errors, so I assumed i was going in the wrong direction. I'll try your solutions, thanks!

  6. #6
    Join Date
    Dec 2016
    Posts
    3
    Platforms
    Windows

    Default Re: C++ Memory Leak?

    Okay, i've implemented vectors, and as much as i think it's working, it's taking an enormous amount of time to go through my for loops... Is that normal?
    This is my implementation of one of the functions. Please bare in mind that this function runs on 800,000 values in data:

    Qt Code:
    1. std::vector<double> Matrix::getMatrixVals() { //Function which returns the values in the data vector
    2. std::cout << "4" << std::endl;
    3. std::vector<double> matrixVals; //Declaring the vector
    4.  
    5. int size = M * N;
    6.  
    7. matrixVals = std::vector<double>(M*N);
    8.  
    9.  
    10. for (int i = 0; i < size; i++) { //Loops through as many values as there are in the matrix
    11. matrixVals[i] = data[i]; //Replacing every value of the vector as it goes
    12. }
    13.  
    14. return matrixVals; //Returning a double array
    15. } //End of the getmatrixvals function
    To copy to clipboard, switch view to plain text mode 


    Edit** Using .resize() has improved performance, but overall this still takes a good few minutes(i've not had chance to see it run to the end yet). Clearly something else is wrong.
    Last edited by dannyhodge; 9th December 2016 at 19:31.

  7. #7
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: C++ Memory Leak?

    Vectors are basically just wrappers around arrays, a way to make copying and memory handling easier.

    You can even retrieve the underlying array with the data() method if you want to try looping over that or using things like memcpy.
    e.g.
    Qt Code:
    1. memcpy(matrixVals.data(), &data, size * sizeof(double));
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  8. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: C++ Memory Leak?

    it's taking an enormous amount of time to go through my for loops
    Well for one thing it looks like you are unnecessarily making copies of arrays. In your "getMatrixVals" method, you could simply rewrite it as:

    Qt Code:
    1. const std::vector<double> & Matrix::getMatrixVals() const { //Function which returns the values in the data vector
    2. std::cout << "4" << std::endl;
    3. return data;
    4. } //End of the getmatrixvals function
    To copy to clipboard, switch view to plain text mode 

    Why? Because you are using vectors to store your data, there is no need to make a copy of it for return. You can simply return a reference to the member variable. Because it is declared as a const vector, the caller can't modify it, and because it is a const method, the compiler knows that the class instance won't be modified so it can optimize a bit better.

    Your caller gets back a const reference to a vector. It can either assign that to a const vector reference (in which case no copying is done) or assign it to a vector variable, in which case a copy is made. The caller determines when the copy is made, not the Matrix class.

    Qt Code:
    1. const std::vector< double > & noCopy = myMatrix.getMatrixVals(); // doesn't make a copy of "data"
    2. std::vector< double > copy = myMatrix.getMatrixVals(); // makes a copy
    3.  
    4. // from here onward, the usage is identical, except that "copy" can change the values in the vector, but "noCopy" can't.
    5. // "copy" has its own version of the data, which it is free to modify without any change to the data in myMatrix.
    To copy to clipboard, switch view to plain text mode 

    You can probably find other places in your code where these copies are being made, only to be thrown away. The rules of thumb are, whenever a method does not modify the information stored in the class instance, declare the function as "const", use std::vector<> or other container classes from the STL rather than raw C++ arrays wherever possible, and return references to the data whenever possible instead of making copies.

    it's taking an enormous amount of time to go through my for loops
    We did some performance testing a while back, using Microsoft VC++ on Windows. We found that using STL iterators was up to an order of magnitude slower than using operator[]() on vectors, and that operator[]() was slower than using pointers, but not by a lot, maybe a factor of two:

    Qt Code:
    1. std::vector< double > myVector( 100000, 42.0 );
    2.  
    3. // Slowest, by 10x
    4. std::vector< double >::iterator it = myVector.begin();
    5. std::vector< double >::iterator eit = myVector.end();
    6. while ( it != eit )
    7. {
    8. double v = *it;
    9. // do something with v
    10. it++;
    11. }
    12.  
    13. // Fast
    14. long nPts = myVector.size();
    15. for ( long nPt = 0; nPt < nPts; ++nPt )
    16. {
    17. double v = myVector[ nPt ];
    18. // do something with v
    19. }
    20.  
    21. // Fastest
    22. double * pV = &(myVector[0]);
    23. for ( long nPt = 0; nPt < nPts; ++nPt, pV++ )
    24. {
    25. double v = *pV;
    26. // do something with v
    27. }
    To copy to clipboard, switch view to plain text mode 

    You can do the last loop because the STL guarantees that std::vector elements occupy contiguous memory, in the same way as if you had used operator new[]() to allocate a C++ array.
    Last edited by d_stranz; 10th December 2016 at 18:49.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. Qt & Memory Leak
    By fanoI in forum Qt Programming
    Replies: 7
    Last Post: 31st October 2013, 08:53
  2. memory leak in qml
    By jindoniit in forum Qt Quick
    Replies: 6
    Last Post: 26th September 2011, 10:16
  3. Qt dll + memory leak
    By Fastman in forum Qt Programming
    Replies: 3
    Last Post: 2nd August 2009, 13:28
  4. memory leak
    By mattia in forum Newbie
    Replies: 18
    Last Post: 16th January 2008, 10:22
  5. Memory leak?
    By Enygma in forum Qt Programming
    Replies: 10
    Last Post: 4th September 2007, 16:24

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.