Possible Memory Leak?

I've written a short, multi-source file program in native C++ using VS 2010 (I'm on Windows 7). I had to allocate some memory on the heap for an unsigned int array. During the program duration, I pass that array to functions like so:
function(array);
And at the end of the day I call delete [] array to free the memory I allocated.

But after I run the program once or twice, my computer slows down tremendously. I close my program, but my computer doesn't clear up. It takes several minutes just to bring Task Manager to look at the active processes and CPU usage, but I don't see anything on the list hogging up lots of memory and CPU usage is below 25%, even though I can hear the fan spinning as hard as it can.

I end up having to reboot the system to get everything back to normal. My first thought was that I have a memory leak somewhere, but I couldn't find it after spending days going through the code over and over. For the one new statement I have, I also have a delete which is called at the end of the main function. I also have quite a large char array on the stack, but that shouldn't be a problem since stack space frees itself when the program closes. I also declare and initialize a few std::vectors inside some other functions that are called multiple times, but I was under the impression vectors managed their own memory for me.

Since I'm somewhat new to programming, I guess I may be misreading the problem entirely. Could symptoms like I'm describing be the result of a memory leak?

I can post the code if you guys ask, but I'm not sure if I need to, and since it's a few hundred lines I don't want to clutter up forum space unnecessarily.
Operating system will free all memory program requested after it closes. If you have instant slowdown for several seconds after program closing, it can be system managing pagefile, but in your case it is probably something else.
Post the code, its not obvious where the "problem" is coming from. May be some external programs running in background or rarely, your program.
I doubt it's some external program, the slowdown happens pretty consistently after running my program once or twice.

Here's the code, it generates a 512x512 .bmp map of an island based on some user input. Here is the first half, main.cpp and main.h:
main.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "main.h"

int main(int argc, char *argv[])
{
	//Resolution: image is square, res X res pixels in size
	//3 components (RGB) per pixel
	const unsigned int res = 512;
	unsigned char imageData[res*res*3];

	//Land map: true if pixel is land,
	//false if pixel is ocean
	unsigned int *landMap = new unsigned int[res*res];

	//Get a seed to pass into the populateLandMap function
	while (true){
		std::cout << "\nEnter a seed: ";
		char seedChar = std::getchar();
		std::vector<char> charVecSeed;
		while (seedChar != '\n'){
			charVecSeed.push_back(seedChar);
			seedChar = std::getchar();
		}
		unsigned int numPlaces = charVecSeed.size();
		unsigned int curIter = 0;
		unsigned int seed = 0;
		while (curIter < numPlaces){
			int place = numPlaces - curIter - 1;
			//Convert character input to a single digit integer,
			//Then multiply by its place (eg. hundreds, tens, ones)
			//and add to current total
			//Ex. 135 = 1(100) + 3(10) + 5(1)
			seed += ((int(charVecSeed[curIter]) - '0') * power(10, place));
			curIter++;
		}

		std::cout << "\nEnter a threshold from 0 to 255: ";
		char threshChar = std::getchar();
		std::vector<char> charVecThresh;
		while (threshChar != '\n'){
			charVecThresh.push_back(threshChar);
			threshChar = std::getchar();
		}
		numPlaces = charVecThresh.size();
		curIter = 0;
		int thresh = 0;
		while (curIter < numPlaces){
			int place = numPlaces - curIter - 1;
			//Same method as for the seed
			thresh += ((int(charVecThresh[curIter]) - '0') * power(10, place));
			curIter++;
		}

		populateLandMap(landMap, res, seed, thresh);

		makeLand(imageData, landMap, res);

		makeBeach(imageData, landMap, res);
		makeBeach(imageData, landMap, res);
		makeBeach(imageData, landMap, res);

		clearOutliersV2(imageData, landMap, res);

		unsigned int testInt = SOIL_save_image("da_map.bmp", SOIL_SAVE_TYPE_BMP, res, res, 3, &imageData[0]);

		std::cout << "\n\nEnter n to make a new map, or q to quit: ";
		char passChar = std::getchar();
		char newline = std::getchar();
		if (passChar == 'q'){
			break;
		}
	}

	delete [] landMap;
    return 0;
}

main.h:
1
2
3
4
#include <SOIL.h>
#include <cstdio>
#include <iostream>
#include "logic.h" 

And part of the second half, logic.cpp and logic.h:
logic.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <math.h>
#include "simplexnoise.h"
#include <vector>
#include <algorithm>

void clearOutliersV2(unsigned char imageData[], unsigned int landMapArray[], const unsigned int res);
// getIndex returns landMapArray indices
// NOT color array indices
int getIndex(unsigned int X, unsigned int Y, const unsigned int res);
unsigned int getX(unsigned int Y, const unsigned int res, unsigned int colorIndex);
unsigned int getY(const unsigned int res, unsigned int colorIndex);
bool isPixelInCircle(unsigned int pixIndex, unsigned int res, unsigned int radius);
void makeBeach(unsigned char imageData[], unsigned int landMapArray[], const unsigned int res);
void makeLand(unsigned char imageData[], unsigned int landMapArray[], const unsigned int res);
void populateLandMap(unsigned int landMapArray[], const unsigned int res, int seed, int threshold);
int power(int base, int exponent);

logic.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include "logic.h"
#include <iostream>

/*
COORDINATE SYSTEM:
Example layout of 4x4 pixel file: 

(0, 0) | (1, 0) | (2, 0) | (3, 0)
(0, 1) | (1, 1) | (2, 1) | (3, 1)
(0, 2) | (1, 2) | (2, 2) | (3, 2)
(0, 3) | (1, 3) | (2, 3) | (3, 3)

*/

void clearOutliersV2(unsigned char imageData[], unsigned int landMapArray[], const unsigned int res){
	std::vector<unsigned int> colorIndices;

	unsigned int curIter = 0;
	unsigned int maxIter = res*res*3;

	// Get colorIndices relating to those pixels 41 away from the edge 
	// that are not ocean.
	// Don't need to clear edge since that's already ocean due to
	// makeBeach passes.
	while (curIter < maxIter){
		unsigned int pixNumber = (curIter/3);// + 1;
		unsigned int Y = int(floor(float(pixNumber)/float(res)));
		unsigned int X = pixNumber - res*Y;// - 1;
		if ((X == 41) || (X == (res-42)) || (Y == 41) || (Y == (res-42))){
			if (landMapArray[getIndex(X, Y, res)] != 0){
				colorIndices.push_back(curIter);
			}
		}
		curIter+= 3;
	}

	// Now, colorIndices contains color indices to all pixels on 
	// the edge of the checking boundary that aren't ocean (and need to be changed)

	curIter = 0;
	
	// Unspecified amount of passes, as many as we need:
	while (true){
		// If we've gone through every pixel in the list, 
		// return:
		if (curIter == colorIndices.size()){
			return;
		}


		unsigned int Y = getY(res, colorIndices[curIter]);
		unsigned int X = getX(Y, res, colorIndices[curIter]);

		// Set pixel to ocean:
		imageData[colorIndices[curIter]] =   char(0);
		imageData[colorIndices[curIter]+1] = char(0);
		imageData[colorIndices[curIter]+2] = char(191);

		landMapArray[(colorIndices[curIter])/3] = 0;

		// Unclear which direction code scans in.
		// We need to check on all sides of a pixel. 
		// Checking up and down:
		unsigned int checkUpIndex = getIndex(X, Y-1, res);
		unsigned int checkDownIndex = getIndex(X, Y+1, res);
		unsigned int checkRightIndex = getIndex(X+1, Y, res);
		unsigned int checkLeftIndex = getIndex(X-1, Y, res);
		// Pixel above is land (and so connected to the one we just cleared):
		if (landMapArray[checkUpIndex] != 0){
			// Check if pixel above is already in the vector, 
			// and only add it if it isn't already there: 
			if (std::find(colorIndices.begin(), colorIndices.end(), (checkUpIndex*3)) == colorIndices.end()){
				// Add it to the vector to be set to ocean eventually:
				colorIndices.push_back(checkUpIndex*3);

				std::cout << "\nPixel above added.";
			}
		}
		// Pixel below is land (and so connected to the one we just cleared):
		if (landMapArray[checkDownIndex] != 0){
			// Check if pixel below is already in the vector, 
			// and only add it if it isn't already there: 
			if (std::find(colorIndices.begin(), colorIndices.end(), (checkDownIndex*3)) == colorIndices.end()){
				// Add it to the vector to be set to ocean eventually:
				colorIndices.push_back(checkDownIndex*3);

				std::cout << "\nPixel below added.";
			}
		}
		// Pixel to the right is land (and so connected to the one we just cleared):
		if (landMapArray[checkRightIndex] != 0){
			// Check if pixel to the right is already in the vector, 
			// and only add it if it isn't already there: 
			if (std::find(colorIndices.begin(), colorIndices.end(), (checkRightIndex*3)) == colorIndices.end()){
				// Add it to the vector to be set to ocean eventually:
				colorIndices.push_back(checkRightIndex*3);

				std::cout << "\nPixel to the right added.";
			}
		}
		// Pixel to the left is land (and so connected to the one we just cleared):
		if (landMapArray[checkLeftIndex] != 0){
			// Check if pixel to the left is already in the vector, 
			// and only add it if it isn't already there: 
			if (std::find(colorIndices.begin(), colorIndices.end(), (checkLeftIndex*3)) == colorIndices.end()){
				// Add it to the vector to be set to ocean eventually:
				colorIndices.push_back(checkLeftIndex*3);

				std::cout << "\nPixel to the left added.";
			}
		}

		curIter++;
		std::cout << "\nPass " << curIter << " done.";
		if (curIter >= 1000000){
			return;
		}
	}

	return;
}

// Convert X and Y values into array index
// NOT color array index
int getIndex(unsigned int X, unsigned int Y, const unsigned int res){
	return (res*Y + X);
}

unsigned int getX(unsigned int Y, const unsigned int res, unsigned int colorIndex){
	unsigned int pixNumber = (colorIndex/3);// + 1;
	unsigned int X = pixNumber - res*Y;// - 1;
	return X;
}

unsigned int getY(const unsigned int res, unsigned int colorIndex){
	unsigned int pixNumber = (colorIndex/3);
	unsigned int Y = int(floor(float(pixNumber)/float(res)));
	return Y;
}

// isPixelInCircle: returns true if pixel in character array at index
// pixIndex (to be converted to (X, Y) values) lies within or on a circle
// centered at (res/2, res/2) with the given radius
bool isPixelInCircle(unsigned int pixIndex, unsigned int res, unsigned int radius){
	unsigned int X = res/2;
	unsigned int Y = res/2;
	unsigned int center[2] = {X, Y};

	unsigned int pixNumber = pixIndex + 1;
	Y = int(floor(float(pixNumber)/float(res)));
	X = pixNumber - res*Y - 1;
	unsigned int pixelCoord[2] = {X, Y};

	if ((pixelCoord[0]-center[0])*(pixelCoord[0]-center[0]) + (pixelCoord[1]-center[1])*(pixelCoord[1]-center[1]) <= radius*radius){
		return true;
	}
	else return false;
}

Sorry for all the walls of text, it's why I wasn't sure if I should post the code in the first place.

I had to break logic.cpp up into two halves to fit under the post character limit. Second half:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
void makeBeach(unsigned char imageData[], unsigned int landMapArray[], const unsigned int res){
	
	//local vector to hold all curIters that correspond to beach pixels:
	std::vector<int> beachIterVec;

	int curIter = 0;
	int maxIter = res*res*3;
	while (curIter < maxIter){
		unsigned int pixNumber = (curIter/3);// + 1;
		unsigned int Y = int(floor(float(pixNumber)/float(res)));
		unsigned int X = pixNumber - res*Y;// - 1;
		if (X <= 40 || X >= (res-41) || Y <= 40 || Y >= (res-41)){
			//Pixel is on the edge of the screen
			imageData[curIter] =   char(0);
			imageData[curIter+1] = char(0);
			imageData[curIter+2] = char(191);

			landMapArray[getIndex(X, Y, res)] = 0;
		}
		else {
			if (landMapArray[getIndex(X, Y, res)] == 0){
				//Pixel is ocean
				if ((landMapArray[getIndex(X+1, Y, res)] != 0) || (landMapArray[getIndex(X-1, Y, res)] != 0) || (landMapArray[getIndex(X, Y+1, res)] != 0) || (landMapArray[getIndex(X, Y-1, res)] != 0)){
					//Pixel is touched by land
					//Paint it beach colored
					imageData[curIter] =   char(242);
					imageData[curIter+1] = char(242);
					imageData[curIter+2] = char(92);

					//Add this value of curIter to the beach iter vec:
					beachIterVec.push_back(curIter);
				}
			}
		}
		curIter += 3;
	}

	curIter = 0;
	maxIter = beachIterVec.size();
	while (curIter < maxIter){
		//This is beach:
		landMapArray[(beachIterVec[curIter]/3)] = 2;
		curIter++;
	}
}


void makeLand(unsigned char imageData[], unsigned int landMapArray[], const unsigned int res){
	unsigned int curIter = 0;
	unsigned int maxIter = res*res*3;
	while (curIter < maxIter){
		unsigned int pixNumber = curIter/3;
		unsigned int Y = int(floor(float(pixNumber)/float(res)));
		unsigned int X = pixNumber - res*Y;
		if (landMapArray[(curIter/3)] != 0){
			//This is land:

			//This is grass:
			if (landMapArray[curIter/3] == 1){
				//Simplex distort for grass "texture":
				float simplexValue = scaled_octave_noise_2d(4.0f, 1.0f, 0.1f, -50.0f, 50.0f, float(X), float(Y));

				imageData[curIter] =   char(0);
				imageData[curIter+1] = char(191+int(simplexValue));
				imageData[curIter+2] = char(16);
			}
			else if (landMapArray[curIter/3] == 3){
				//Simplex distort for stone "texture":
				float simplexValue = scaled_octave_noise_2d(4.0f, 1.0f, 0.1f, -20.0f, 25.0f, float(X), float(Y));

				imageData[curIter] =   char(173+int(simplexValue));
				imageData[curIter+1] = char(173+int(simplexValue));
				imageData[curIter+2] = char(173+int(simplexValue));
			}
			else if (landMapArray[curIter/3] == 4){
				//Simplex distort for snow "texture":
				float simplexValue = scaled_octave_noise_2d(4.0f, 1.0f, 0.1f, -35.0f, 0.0f, float(X), float(Y));

				imageData[curIter] =   char(255+int(simplexValue));
				imageData[curIter+1] = char(255+int(simplexValue));
				imageData[curIter+2] = char(255+int(simplexValue));
			}
		}
		else {
			//This is ocean:
			imageData[curIter] =   char(0);
			imageData[curIter+1] = char(0);
			imageData[curIter+2] = char(191);
		}
		curIter += 3;
	}
	return;
}


//Fills a res*res sized unsigned int array on the heap 
//with values, 1 if that pixel is land, 0 if it's ocean,
//based on values from simplex noise-generated texture
void populateLandMap(unsigned int landMapArray[], const unsigned int res, int seed, int threshold){
	const unsigned int resAct = 512;
	unsigned int curIter = 0;
	unsigned int maxIter = resAct*resAct;
	while (curIter < maxIter){
		unsigned int pixNumber = curIter + 1;
		unsigned int Y = int(floor(float(pixNumber)/float(resAct)));
		unsigned int X = pixNumber - resAct*Y - 1;
		float curSimplexValue = scaled_octave_noise_2d(4.0f, 0.5f, 0.005f, 0.0f, 255.0f, float(X + seed), float(Y + seed));

		// BE CAREFUL - must not write beyond the landMapArray!
		if (curSimplexValue > float(threshold+25)){
			//Snow
			landMapArray[curIter] = 4;
		}
		else if (curSimplexValue > float(threshold+19)){
			//Stone
			landMapArray[curIter] = 3;
		}
		else if (curSimplexValue > float(threshold)){
			//Grass
			landMapArray[curIter] = 1;
		}
		else {
			landMapArray[curIter] = 0;
		}

		curIter++;
	}
	return;
}

//Takes a to the power b
//returns an int rather than a double or float
int power(int base, int exponent){
	int curIter = 1;
	int ans = 1;
	while (curIter <= exponent){
		ans *= base;
		curIter++;
	}
	return ans;
}

It also relies on a simplex noise generator I found online, and SOIL, the Simple OpenGL Image Library, which I use to create the .bmp file.

I'm mainly concerned the problem comes from bad practice. I'm mostly self-taught, so I probably developed some bad habits along the way. Maybe I'm passing the landMap and imageData arrays into the logic functions the wrong way, or maybe there's something wrong with populating vectors outside of the main function, or something.
Last edited on
Topic archived. No new replies allowed.