maddogandnoriko
maddogandnoriko

Reputation: 1002

find memory usage

I have a table with 150x150 cells which each have a colored background and a small image/symbol in them. Additionally each cell can have zero or more of it's borders set also. The user can change and add borders and change the cell color and cell. This all works pretty well using jquery and it is just a plain html table.

At the end of the user experience I am making a pdf of this table for them to download. This is a big job and takes a while, which is not my main concern now. jQuery gathers the table data in an array and sends it to php to recreate it as an image using the gd library.

So for each cell I was drawing a rectangle of the correct color on a large image, loading the symbol image and resampling it on to the large image, drawing the borders and imagedestroy the symbol image, it worked but took 1 minute. I changed my strategy to make a small colored rectangke impose the image on it and cache it in an array to be quickly used again. That sped my time up and brought it down to 30ish seconds, but now I am exhausting memory.

I am breaking the table down into 50 cell blocks so each fits on a page, each block is made into an image and saved to disk, the next is made and saved, etc. Each time the gd image is destroyed. Then all the blocks are inserted into the pdf.

So after all that, my question is how do I figure out where the memory is being used so I can try to free it up? I have posted the main function I think is causing the issue below. In my test there are up to 30 different symbols/colors images that are 25pxX25px, these are the images that are cached in an array.

I hope I have provided enough info and my problem is clear enough.

Thank you for your time, Todd

//make one "block" of stitches returns image file name.
//function makeStitchChartBlock($img, $startX, $startY, $endX, $endY, $caption, $brand){
function makeStitchChartBlock($stitchChartArray, $startX, $startY, $endX, $endY, $caption, $brand,$blockNumber){
    global $threadColours;
    $stitchCache=array();
    $saveTo = 'result'.$blockNumber.'.jpeg';
    // calculate size of block
    $numRows=($endY-$startY);
    $numColumns=($endX-$startX);
    $heightOfBlock = $numRows*SYMBOL_SIZE; //in pixels --- used to determine size of image to make for block
    $widthOfBlock = $numColumns*SYMBOL_SIZE; //in pixels

    //----plus any extra for captions grid lines
    $heightOfBlock += (($endY-$startY)+1); //each stitch has a grid line before it and the last one also has on after it
    $widthOfBlock += (($endX-$startX)+1);

    // create image size of block to put stitches in
    $newBlockImage = imagecreatetruecolor($widthOfBlock,$heightOfBlock);
    $backStitchColor = imagecolorallocate($newBlockImage, 0, 0, 0);
    // insert caption????
    //draw grid lines
    //$newBlockImage = addGridToImage($newBlockImage);

    //keep track of where to start next cell top left
    $blockX=0; 
    $blockY=0;

    for($y = $startY; $y < $endY; $y++){ //for each pixel in height, move down 1 "row" each iteration
      //echo "<tr>";
      for($x = $startX; $x < $endX; $x++){ // "draws" a row (for each y pixel)
        //rgb(75, 90, 60)
        //x and y are column and row #'s        
        list($r, $g, $b) = getRGBs($stitchChartArray[$y][$x][0]); //get the rgb values for the cell
        $stitchColor = imagecolorallocate($newBlockImage, $r, $g, $b);

        //calculate x & y start positons
        $stitchStartX=($blockX*SYMBOL_SIZE)+$blockX+1; //account for each previous stitch and the grid line, then add one for new grid line
        $stitchStartY=($blockY*SYMBOL_SIZE)+$blockY+1;
        $stitchEndX=$stitchStartX+(SYMBOL_SIZE);
        $stitchEndY=$stitchStartY+(SYMBOL_SIZE);

        /* make a symbol cell image with/without color and save it in the cache */
        if(!isset($stitchCache[$r][$g][$b]))
        {
            //create new image
            $stitchCache[$r][$g][$b] = imagecreatetruecolor(SYMBOL_SIZE,SYMBOL_SIZE);
            $stitchCacheColor = imagecolorallocate($stitchCache[$r][$g][$b], $r, $g, $b);
            //draw colored rectangle
            imagefilledrectangle($stitchCache[$r][$g][$b], 0, 0, SYMBOL_SIZE-1, SYMBOL_SIZE-1, $stitchCacheColor);
            //add the symbol
            $symbolFile=$stitchChartArray[$y][$x][1];
            if($symbolFile){
                $symbolImage = imagecreatefrompng($symbolFile);
                imagecopyresampled ($stitchCache[$r][$g][$b],$symbolImage,0,0,0,0,SYMBOL_SIZE-1,SYMBOL_SIZE-1,imagesx($symbolImage), imagesy($symbolImage) );
                imagedestroy($symbolImage);
            }
        }

        //add image from cache to the block image
        imagecopyresampled ($newBlockImage,$stitchCache[$r][$g][$b],$stitchStartX, $stitchStartY,0,0,SYMBOL_SIZE,SYMBOL_SIZE,SYMBOL_SIZE,SYMBOL_SIZE);

        //add the backstitch lines(borders)
        if($stitchChartArray[$y][$x][2]>1) //top
        {
            imagefilledrectangle($newBlockImage, $stitchStartX, $stitchStartY, $stitchEndX, $stitchStartY+1, $backStitchColor);
        }
        if($stitchChartArray[$y][$x][3]>1) //right
        {
            imagefilledrectangle($newBlockImage, $stitchEndX-1, $stitchStartY, $stitchEndX, $stitchEndY, $backStitchColor);
        }
        if($stitchChartArray[$y][$x][4]>1) //bottom
        {
            imagefilledrectangle($newBlockImage, $stitchStartX, $stitchEndY-1, $stitchEndX, $stitchEndY, $backStitchColor);
        }
        if($stitchChartArray[$y][$x][5]>1) //left
        {
            imagefilledrectangle($newBlockImage, $stitchStartX, $stitchStartY, $stitchStartX+1, $stitchEndY, $backStitchColor);
        }

       //advance x position
       $blockX++;
      }
       //advance y position
      //reset x
      $blockX=0;
      $blockY++;
    }

    imagejpeg($newBlockImage, $saveTo);
    imagedestroy($newBlockImage);


//dump stitch cache
foreach($stitchCache as $r)
{
    foreach($r as $g)
    {
        foreach($g as $b=>$data)
        {
            imagedestroy($data);
        }
    }
}
        return $saveTo;
    }

Upvotes: 1

Views: 166

Answers (1)

liquorvicar
liquorvicar

Reputation: 6106

I would start (if you haven't already) by getting a good IDE and a debugger as these will be invaluable tools. In this instance you may be able to use a profiler to work out where the memory is being used. Failing that some good ole' manual debugging code, say

$memory = memory_get_usage();

as the first line inside your inner loop. Then when you step through using the debugger you'll be able to see where the memory is ramping up.

btw, using global variables is generally not a good idea. You might want to pass in $threadColours as a parameter or look at other ways of getting that data into the function.

Upvotes: 1

Related Questions