C++ Memory Leak?

danhodge

In Runtime
Messages
324
Location
UK
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):

Code:
	int i = 768;
	int j = 1024;

	int startRow = 0;
	int endRow = 49;
	int startCol = 0;
	int endCol = 36;

	Matrix SceneMatrix(i, j, input_data);                                                        //Matrix of cluttered_scene
	Matrix WallyMatrix(49, 36, wally_data);                                                      //Matrix of wally

	Matrix BestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol);                //Matrix to contain the best result that matches wally, based on a subset of SceneMatrix
	Matrix BestMatrix2 = BestMatrix;                                                             //Set to same details as BestMatrix(Copy constructer runs here)
	Matrix BestMatrix3 = BestMatrix;										          	       	//Set to same details as BestMatrix(Copy constructer runs here)

	

	int ans = 0;

	cout << "Would you like to use the Sum Of Squared Differences(1) to find Wally, or Normalized Correlation(2)?" << endl;

	cin >> ans;

	if (ans == 1) {                                                                        //If SSD
		BestMatrix.setScore(SumOfSquaredDifferences(WallyMatrix, BestMatrix));
		BestMatrix2.setScore(SumOfSquaredDifferences(WallyMatrix, BestMatrix2));
		BestMatrix3.setScore(SumOfSquaredDifferences(WallyMatrix, BestMatrix3));

	}
	else if(ans == 2) {                                                                    //If NC
		BestMatrix.setScore(NormalisedCorrelation(WallyMatrix, BestMatrix));
		BestMatrix2.setScore(NormalisedCorrelation(WallyMatrix, BestMatrix2));
		BestMatrix3.setScore(NormalisedCorrelation(WallyMatrix, BestMatrix3));
	}

	
	int corrStartRow = 0;      //Pos of best option
	int corrEndRow = 0;
	int corrStartCol = 0;
	int corrEndCol = 0;

	int corrStartRow2 = 0;     //Pos of second best option
	int corrEndRow2 = 0;
	int corrStartCol2 = 0;
	int corrEndCol2 = 0;

	int corrStartRow3 = 0;     //Pos of third best option
	int corrEndRow3 = 0;
	int corrStartCol3 = 0;
	int corrEndCol3 = 0;









	double moveValue = 6;   //Amount that the scanner will shift each iteration

	for (endRow; endRow < (i - 49); endRow += moveValue, startRow+= moveValue) {   //Loop through each row

		for (endCol; endCol < (j - 36); endCol += moveValue, startCol += moveValue) {  //Loop through each column

			
			  Matrix TestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol);  //Matrix that will be tested against current best matrix

			  if (ans == 1) {         //If SSD
				  TestMatrix.setScore(SumOfSquaredDifferences(WallyMatrix, TestMatrix));  //Test score using SSD
			  }
			  else if (ans == 2) {    //If NC
				  TestMatrix.setScore(NormalisedCorrelation(WallyMatrix, TestMatrix));  //Test score using NC
			  }

			  if (ans == 1) {                                            //If SSD
				  if (TestMatrix.getScore() < BestMatrix.getScore()) {   //Best option

					  BestMatrix = TestMatrix;      //Set BestMatrix and a set of coords to the test matrix, as this is better than the previous BestMatrix
					  corrStartRow = startRow;      //Coords to be used when drawing rectangle
					  corrEndRow = endRow;
					  corrStartCol = startCol;
					  corrEndCol = endCol;

				  }
				  else if(TestMatrix.getScore() < BestMatrix2.getScore()) {   //Second best option

				  BestMatrix2 = TestMatrix;      //Set BestMatrix2 and a set of coords to the test matrix, as this is better than the previous BestMatrix2
				  corrStartRow2 = startRow;      //Coords to be used when drawing rectangle
				  corrEndRow2 = endRow;
				  corrStartCol2 = startCol;
				  corrEndCol2 = endCol;

				  } 
				  else if (TestMatrix.getScore() < BestMatrix3.getScore()) {   //Third best option

					  BestMatrix3 = TestMatrix;   //Set BestMatrix3 and a set of coords to the test matrix, as this is better than the previous BestMatrix3
					  corrStartRow3 = startRow;   //Coords to be used when drawing rectangle
					  corrEndRow3 = endRow;
					  corrStartCol3 = startCol;
					  corrEndCol3 = endCol;

				  }

			}   //end if ans == 1 (SSD)
			   else if (ans == 2) {										//If NC
				  if (TestMatrix.getScore() > BestMatrix.getScore()) {  //Best option

					  BestMatrix = TestMatrix;   //Set BestMatrix and a set of coords to the test matrix, as this is better than the previous BestMatrix
					  corrStartRow = startRow;   //Coords to be used when drawing rectangle
					  corrEndRow = endRow;
					  corrStartCol = startCol;
					  corrEndCol = endCol;

				  }
				  else if (TestMatrix.getScore() > BestMatrix2.getScore()) { //Second best option

					  BestMatrix2 = TestMatrix;   //Set BestMatrix2 and a set of coords to the test matrix, as this is better than the previous BestMatrix2
					  corrStartRow2 = startRow;   //Coords to be used when drawing rectangle
					  corrEndRow2 = endRow;
					  corrStartCol2 = startCol;
					  corrEndCol2 = endCol;

				  }
				  else if (TestMatrix.getScore() > BestMatrix3.getScore()) {  //Third best option

					  BestMatrix3 = TestMatrix;    //Set BestMatrix3 and a set of coords to the test matrix, as this is better than the previous BestMatrix3
					  corrStartRow3 = startRow;    //Coords to be used when drawing rectangle
					  corrEndRow3 = endRow;
					  corrStartCol3 = startCol;
					  corrEndCol3 = endCol;

				  }
			  }  //End if ans == 2(NC)
			  
		}   //End for loop of columns
		endCol = 36;  //Move to next row
		startCol = 0;
		
	}  //End for loop of rows

And the Matrix Class:
Code:
#pragma once

class Matrix {                                                            //This matrix class allows me to make a new object for each matrix I need

public:                                                                   //Allows anything that is public to be accessed (e.g. matrix1.getBlock)


	Matrix(int sizeR, int sizeC, double input_data[]);                    //Class constructer
	~Matrix();                                                            //Class Destructer
	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
	double* Matrix::getMatrixVals();  //Function which returns the data array in a matrix
	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)
	void setScore(double Score);      //Function which sets the score variable
	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)
	Matrix(const Matrix& e);          //Copy Constructer



private:                                //Can't be accessed outside of Matrix class
	int M, N;                           //Amount of rows and columns in the matrix
	double *data;                       //The data read into the matrix
	double *newData;                    //The new set of data, taken out of the data variable, based on the getBlock function
	double score;                       //The score, assigned by either the Sum of Squared Differences function, or the Normalized Correlation function
	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)
                                        //To be used for putting a square around wally
};

Matrix::Matrix(int sizeR, int sizeC, double input_data[]) {  //The Class Constructer (runs whenever a new Matrix object is created)

	 M = sizeR; //M = height
	 N = sizeC; //N = width


	data = new double[M*N];                   //Sets the total space of the data array
	newData = new double[36*49];              //Sets the total space of the new data array
	posInScene = new int[36*49];              //Sets the total space of the position in scene array

	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
		data[ii] = input_data[ii];            //Adding each value in the data array, one by one
	}
} 


Matrix::~Matrix() {  //The class destructer, which runs every time a matrix is deleted (included when it is passed through a function as a reference)


}                    //End of class destructer



Matrix Matrix::getBlock(int startRow, int endRow, int startCol, int endCol) {    //Function which returns a Matrix based on a start/end row/column

	

	int currentCol = startCol;
	int currentRow = startRow; //Temporary variables used to retain value of start row/start column
	int counter = 0;
	

		for (currentRow; currentRow < endRow; currentRow++) {

			for (currentCol; currentCol < endCol; currentCol++) {    //The  nested for loop means this will run endCol * endRow times (in this case, 36 * 49 times)	

			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
			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
			counter++;                                               //Incrementing the counter
		}       //End of the currentCol for loop
		currentCol = startCol;                                       //After finishing a row, this moves onto the next one
	 }          //End of the currentRow for loop

	Matrix NewMatrix(endRow - startRow, endCol - startCol, newData);   //The matrix that will be returned as the subset of the original matrix

	return NewMatrix;
} //End getBlock function

Matrix::Matrix(const Matrix& e) { //Copy Constructer

	M = e.M;
	N = e.N;
	data = e.data;
	newData = e.newData;
	score = e.score;
	posInScene = e.posInScene;   ///Whenever a Matrix is copied, each of these variables is set to what it was
} //End copy constructer


double* Matrix::getMatrixVals() {   //Function which returns the values in the data array

	double* matrixVals;             //Declaring the array

	int size = M * N;

	matrixVals = new double[size]; ///Declares the size of the array


	for (int i = 0; i < size; i++) {   //Loops through as many values as there are in the matrix
		
		matrixVals[i] = data[i];       //Replacing every value of the array as it goes
	}

	return matrixVals;                 //Returning a double array
}  //End of the getmatrixvals function


Any suggestions would be fantastic, i'm a little dumbfounded. Oh, and if you're confused about variable names, the assignment was to make a program that can find wally in a scene :p

Thanks a lot,
Danny
 
Last edited:
At least it's finding "wally" and not looking for a "willy" :p.

Man...I haven't touched C++ in like 5 years lmao. I'll try...but not sure how much help I'll be.

So...is it blowing up at all, or just consuming tons of memory processing the loop and still finishing it successfully?

Is it possible to null out any variables during the loop after you've used them? Maybe they're getting stuck in memory.

Looks like your getBlock function is creating a new matrix every time it runs (that would definitely cause a boost in memory consumption)...is that necessary, or can you add to an existing matrix that's passed in by reference?
 
Damn, just when I was starting to think you were a wizard ;)

It seems to end naturally (no errors), but it skips straight to the end, and doesn't even try to run anything on the way. It hits exactly 2GB of memory when it crashes, so i think it's hitting it's limit :omg:

I've been attempting to delete the data (can just delete[] data and delete[] newData i think), not sure what else I can do there.

And even when it's declared outside the brackets like this, it's still doing it:
Code:
Matrix TestMatrix(0, 0, 0);

	double moveValue = 1;   //Amount that the scanner will shift each iteration

	for (endRow; endRow < (i - 49); endRow += moveValue, startRow+= moveValue) {   //Loop through each row

		for (endCol; endCol < (j - 36); endCol += moveValue, startCol += moveValue) {  //Loop through each column


			   TestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol);  //Matrix that will be tested against current best matrix

I'm pretty sure the problem is with TestMatrix, and with the line:
Code:
	   TestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol);  //Matrix that will be tested against current best matrix
But i'm not sure what's going on there (i'm pretty sure it's that line because the problem occured when this part of the program was much simpler, and that was like the only line inside the loop).
 
Damn, just when I was starting to think you were a wizard ;)

It seems to end naturally (no errors), but it skips straight to the end, and doesn't even try to run anything on the way. It hits exactly 2GB of memory when it crashes, so i think it's hitting it's limit :omg:

I've been attempting to delete the data (can just delete[] data and delete[] newData i think), not sure what else I can do there.

And even when it's declared outside the brackets like this, it's still doing it:
Code:
Matrix TestMatrix(0, 0, 0);

	double moveValue = 1;   //Amount that the scanner will shift each iteration

	for (endRow; endRow < (i - 49); endRow += moveValue, startRow+= moveValue) {   //Loop through each row

		for (endCol; endCol < (j - 36); endCol += moveValue, startCol += moveValue) {  //Loop through each column


			   TestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol);  //Matrix that will be tested against current best matrix

I'm pretty sure the problem is with TestMatrix, and with the line:
Code:
	   TestMatrix = SceneMatrix.getBlock(startRow, endRow, startCol, endCol);  //Matrix that will be tested against current best matrix
But i'm not sure what's going on there (i'm pretty sure it's that line because the problem occured when this part of the program was much simpler, and that was like the only line inside the loop).

2 GB is a limit that is imposed by most IDEs unless manually overridden. I did manage to make Visual Studio's internal processes use 4 GB of RAM for the program I was debugging instead of 2, but from what you're describing, it's definitely hitting the limit.
 
2 GB is a limit that is imposed by most IDEs unless manually overridden. I did manage to make Visual Studio's internal processes use 4 GB of RAM for the program I was debugging instead of 2, but from what you're describing, it's definitely hitting the limit.

Source?
 
My own experience. I've used Visual Studio and Eclipse so far, and both have spat the dummy if a program has used more than 2 GB of RAM. Usually they'll kill the program.

I believe this is a preventative measure to stop a program from using all a system's RAM, but hey I don't have an *official* source, so meh.
 
My own experience. I've used Visual Studio and Eclipse so far, and both have spat the dummy if a program has used more than 2 GB of RAM. Usually they'll kill the program.

I believe this is a preventative measure to stop a program from using all a system's RAM, but hey I don't have an *official* source, so meh.

Yeah I've had LINQ queries in VS consume 4GB+ on large datasets during debugging without having to modify anything...so not sure where you saw that I guess.
 
Well, turns out mine could use 5GB, it kept crashing my computer :lol:

I've finally fixed it though. Turns out changing the entire program so that getBlock returned a double instead of a Matrix made everything a hell of a lot easier. Thanks for the help :)
 
Well, turns out mine could use 5GB, it kept crashing my computer :lol:

I've finally fixed it though. Turns out changing the entire program so that getBlock returned a double instead of a Matrix made everything a hell of a lot easier. Thanks for the help :)

Ha! Called it! :p

*snip*

Looks like your getBlock function is creating a new matrix every time it runs (that would definitely cause a boost in memory consumption)...is that necessary, or can you add to an existing matrix that's passed in by reference?
 
Back
Top Bottom