簡體   English   中英

釋放2D數組時發生內存泄漏

[英]Memory leak whilst freeing a 2d array

我正在創建一個Conway的《人生游戲》版本。 它最終將在Arduino上運行並將控制LED,因此內存占用空間非常重要。 看來我有內存泄漏,我相信這種泄漏是在創建二維數組時發生的。 如果有人可以幫助我,我將非常感激。

謝謝,

VLD的輸出是:

c:\projects\gameoflifecpp\gameoflifecpp\gameoflifecpp.cpp (72): GameOfLifeCPP.exe!GenerateGrid + 0xA bytes
c:\projects\gameoflifecpp\gameoflifecpp\gameoflifecpp.cpp (185): GameOfLifeCPP.exe!ProcessGrid + 0x7 bytes
c:\projects\gameoflifecpp\gameoflifecpp\gameoflifecpp.cpp (46): GameOfLifeCPP.exe!wmain + 0x9 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (552): GameOfLifeCPP.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): GameOfLifeCPP.exe!wmainCRTStartup
0x7C817077 (File and line number not available): kernel32.dll!RegisterWaitForInputIdle + 0x49 bytes

代碼是:

// GameOfLifeCPP.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <vld.h>

#define WIDTH 75
#define HEIGHT 88
#define GENERATION_COUNT_LIMIT -1

long _generationCount = 0;

// These get set by controls on the table
long _delay = 1000;
bool _run = true;
bool _trail = true;
bool _randomize = false;
char* _colours = "roy";

int _tmain(int argc, _TCHAR* argv[])
{   
system("pause");

short** grid = GenerateGrid(false);
short** trailGrid = GenerateGrid(true); // This is used to record all prev cells

while(_run)
{
    if (_randomize)
    {
        grid = GenerateGrid(false);
        trailGrid = GenerateGrid(true);
        // Fade out LEDs
        // Clear the historical grids that we compare
        _randomize = false;
        _generationCount = 0;
    }

    OutputGrid(grid, trailGrid);
    if (_trail)
        trailGrid = CalculateTrailGrid(grid, trailGrid);
    short** nextGrid = ProcessGrid(grid);

    // Release the old grid
    for(int i = 0; i < sizeof(nextGrid); i++)
    {
        delete(grid[i]);
    }
    delete(grid);

    grid = nextGrid;
    // We don't want to just sleep we need to find out the start and end time
    Sleep(_delay);

    bool foundRecurance = false; 
    // Need to detect recurence, have a buffer of 5-10 prev grids and one 
    // hundredth ago, one thousanth etc that we compare to.
    _generationCount++;

    if (foundRecurance || _generationCount == GENERATION_COUNT_LIMIT)
        _randomize = true;

    _CrtDumpMemoryLeaks();
    //system("pause");
}
return 0;
}

short** GenerateGrid(bool empty)
{
// The coordinates are y,x because it is simpler to output a row of chars 
// when testing in the command line than it is to output a column of chars
short** grid = new short*[HEIGHT];
for(int y = 0; y < HEIGHT; y++)
{
    short* row = new short[WIDTH];
    for(int x = 0; x < WIDTH; x++)
    {
        // There is no point creating random numbers that we aren't going 
        // to use
        if (empty)
            row[x] = 0;
        else
            row[x] = rand() % 5 == 1 ? 1 : 0; 
        // Might want to adjust this or make it random
    }
    grid[y] = row;
}
return grid;
}

void OutputGrid(short** grid, short** trailGrid)
{
// This is terribly inefficent but I don't care since it is only for 
// testing on my laptop
system("cls");

HANDLE hConsole;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

for(int y = 0; y < HEIGHT; y++)
{
    for(int x = 0; x < WIDTH; x++)
    {
        int curState = grid[y][x];

        if (curState == 0 && _trail) // If it isn't alive then show the trail
            curState = trailGrid[y][x];

        switch (curState)
        {
            case 0:  SetConsoleTextAttribute(hConsole, 0); break;
            case 1: SetConsoleTextAttribute(hConsole, GetColour(0)); break;
            case 2: SetConsoleTextAttribute(hConsole, GetColour(1)); break;
            case -1: SetConsoleTextAttribute(hConsole, GetColour(2)); break;
        }
        //if (curState == 1 || curState == 2)
        //  std::cout << "*";
        //else
            std::cout << " ";
    }
    SetConsoleTextAttribute(hConsole, 15);
    std::cout << std::endl;
}
}

int GetColour(int index)
{
int colour = 0;
switch(_colours[index])
{
    case 'r': colour = 12; break;
    case 'o': colour = 6; break;
    case 'y': colour = 14; break;
}

colour = colour * 16;

return colour;
}

int ProcessCell(short** grid, int x, int y)
{
// Get the value for each of the surrounding cells
// We use the formula (x - 1 + WIDTH) % WIDTH because that means that if the
// Current cell is at 0,0 then top left is WIDTH-1,WIDTH-1 and so on.
// This makes the grid wrap around.
// We don't care if the cells value is 1 or 2 it is either live or dead
int topLeft = (
    grid[(y - 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int top = (grid[(y - 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
int topRight = 
    (grid[(y - 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;

int left = (grid[y][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int self = (grid[y][x] > 0) ? 1 : 0;
int right = (grid[y][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;

int bottomLeft = 
    (grid[(y + 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
int bottom = (grid[(y + 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
int bottomRight = 
    (grid[(y + 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;

// Count up the surrounding cells to decide the current cell's state
int liveCount = topLeft + top + topRight + left + 
    right + bottomLeft + bottom + bottomRight;

int live = 0;
if (self > 0)
{
    // Both are alive, just different colours
    if (liveCount == 2)
        live = 1;
    if (liveCount == 3)
        live = 2;
}
else if (liveCount == 3)
{
    // Brought back to life, we don't care that it is the wrong 
    // colour - it looks better
    live = 1; 
}
return live;
}

short** ProcessGrid(short** grid)
{
short** nextGrid = GenerateGrid(true);
for (int y = 0; y < HEIGHT; y++)
{
    for (int x = 0; x < WIDTH; x++)
    {
        nextGrid[y][x] = ProcessCell(grid, x, y);
    }
}

return nextGrid;
}

short** CalculateTrailGrid(short** grid, short** trailGrid)
{
// Any previously live cells are marked
short** nextGrid = GenerateGrid(true);
for (int y = 0; y < HEIGHT; y++)
{
    for (int x = 0; x < WIDTH; x++)
    {
        int state = grid[y][x];
        if (state == 0)
            state = trailGrid[y][x]; // Not alive currently but was
        if (state != 0)
            state = -1;
        nextGrid[y][x] = state;
    }
}
return nextGrid;
}

在記事本中快速清理5分鍾...應該給您一些想法...避免任何可能的內存泄漏...

#include "stdafx.h"

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <vld.h>
#include <vector>

#define WIDTH 75
#define HEIGHT 88
#define GENERATION_COUNT_LIMIT -1

long _generationCount = 0;

// These get set by controls on the table
long _delay         = 1000;
bool _run           = true;
bool _trail         = true;
bool _randomize     = false;
char* _colours      = "roy";

typedef std::vector<std::vector<short>> grid_t; // Use std::vector

int _tmain(int argc, _TCHAR* argv[])
{   
    system("pause");

    grid_t grid         = GenerateGrid(false);
    grid_t trailGrid    = GenerateGrid(true); // This is used to record all prev cells

    while(_run)
    {
        if (_randomize)
        {
            grid = GenerateGrid(false);
            trailGrid = GenerateGrid(true);
            // Fade out LEDs
            // Clear the historical grids that we compare
            _randomize = false;
            _generationCount = 0;
        }

        OutputGrid(grid, trailGrid);
        if (_trail)
            trailGrid = CalculateTrailGrid(grid, trailGrid);
        grid_t nextGrid = ProcessGrid(grid);

        // Release the old grid

        grid = nextGrid;
        // We don't want to just sleep we need to find out the start and end time
        Sleep(_delay);

        bool foundRecurance = false; 
        // Need to detect recurence, have a buffer of 5-10 prev grids and one 
        // hundredth ago, one thousanth etc that we compare to.
        _generationCount++;

        if (foundRecurance || _generationCount == GENERATION_COUNT_LIMIT)
            _randomize = true;

        _CrtDumpMemoryLeaks();
        //system("pause");
    }
    return 0;
}

grid_t GenerateGrid(bool empty)
{
    // The coordinates are y,x because it is simpler to output a row of chars 
    // when testing in the command line than it is to output a column of chars
    grid_t  grid;
    for(int y = 0; y < HEIGHT; y++)
    {
        std::vector<short> row;
        for(int x = 0; x < WIDTH; x++)
            row[x] = empty ? 0 : rand() % 5 == 1 ? 1 : 0; 
        grid.push_back(row);
    }
    return grid;
}

void OutputGrid(const grid_t& grid, const grid_t& trailGrid)
{
    // This is terribly inefficent but I don't care since it is only for 
    // testing on my laptop
    system("cls");

    HANDLE hConsole;
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    for(int y = 0; y < HEIGHT; y++)
    {
        for(int x = 0; x < WIDTH; x++)
        {
            int curState = grid[y][x];

            if (curState == 0 && _trail) // If it isn't alive then show the trail
                curState = trailGrid[y][x];

            switch (curState)
            {
                case  0: SetConsoleTextAttribute(hConsole, 0);            break;
                case  1: SetConsoleTextAttribute(hConsole, GetColour(0)); break;
                case  2: SetConsoleTextAttribute(hConsole, GetColour(1)); break;
                case -1: SetConsoleTextAttribute(hConsole, GetColour(2)); break;
            }
        }
        SetConsoleTextAttribute(hConsole, 15);
        std::cout << std::endl;
    }
}

int GetColour(int index)
{
    switch(_colours[index])
    {
        case 'r': return 16 * 12;
        case 'o': return 16 * 6;
        case 'y': return 16 * 14;
        default:  return 0;     
    }
}

int ProcessCell(const grid_t& grid, int x, int y)
{
    // Get the value for each of the surrounding cells
    // We use the formula (x - 1 + WIDTH) % WIDTH because that means that if the
    // Current cell is at 0,0 then top left is WIDTH-1,WIDTH-1 and so on.
    // This makes the grid wrap around.
    // We don't care if the cells value is 1 or 2 it is either live or dead
    int topLeft     = (grid[(y - 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int top         = (grid[(y - 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
    int topRight    = (grid[(y - 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;

    int left        = (grid[y][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int self        = (grid[y][x] > 0) ? 1 : 0;
    int right       = (grid[y][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;

    int bottomLeft  = (grid[(y + 1 + HEIGHT) % HEIGHT][(x - 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;
    int bottom      = (grid[(y + 1 + HEIGHT) % HEIGHT][x] > 0) ? 1 : 0;
    int bottomRight = (grid[(y + 1 + HEIGHT) % HEIGHT][(x + 1 + WIDTH) % WIDTH] > 0) ? 1 : 0;

    // Count up the surrounding cells to decide the current cell's state
    int liveCount = topLeft + top + topRight + left + right + bottomLeft + bottom + bottomRight;

    int live = 0;
    if (self > 0)
    {
        // Both are alive, just different colours
        if (liveCount == 2)
            live = 1;
        if (liveCount == 3)
            live = 2;
    }
    else if (liveCount == 3)
    {
        // Brought back to life, we don't care that it is the wrong 
        // colour - it looks better
        live = 1; 
    }
    return live;
}

grid_t ProcessGrid(const grid_t& grid)
{
    grid_t nextGrid = GenerateGrid(true);
    for (int y = 0; y < HEIGHT; y++)
    {
        for (int x = 0; x < WIDTH; x++)     
            nextGrid[y][x] = ProcessCell(grid, x, y);       
    }

    return nextGrid;
}

grid_t CalculateTrailGrid(const grid_t& grid, const grid_t& trailGrid)
{
    // Any previously live cells are marked
    grid_t nextGrid = GenerateGrid(true);
    for (int y = 0; y < HEIGHT; y++)
    {
        for (int x = 0; x < WIDTH; x++)     
            nextGrid[y][x] = state == 0 ? trailGrid[y][x] : -1;     
    }
    return nextGrid;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM