PHP:处理内存和放大器代码内存使用率低

时间:2010-11-12 08:28:32

标签: php memory memory-management

是的我有PHP内存问题。我的主人提供最多。使用64M内存限制,并以某种方式当我上传+裁剪功能超过此内存,并且我收到错误(不总是,但取决于图像大小)

当我上传大约1 mb或更低的图片时,会上传,您可以裁剪并保存。

但是当我上传大约2 mb或更高的图像(我对上传功能的限制为6mb)时,它会上传,然后当您裁剪图像并想要保存时,我会收到“内存不足错误。” / p>

我尝试在gd中的任何函数之后imagedestroy(),我不再使用了,但这并没有影响它。虽然即时通讯仅在案例裁剪中使用GD功能

在上传案例中,还有什么可以解开我的记忆吗?

或者可能一般如何释放php内存使用?

这是我的剧本:

switch($action) {

    case 'upload':


    $userid = $USER;
    $user = getUserInfo($userid);
    $lasttime = $user['showURP']["photo_lasttime"];

    $upload_name = "file";
    $max_file_size_in_bytes = 8388608;
    $extension_whitelist = array("jpg", "gif", "png", "jpeg");

    /* checking extensions */
    $path_info = pathinfo($_FILES[$upload_name]['name']);
    $file_extension = $path_info["extension"];
    $is_valid_extension = false;
    foreach ($extension_whitelist as $extension) {
        if (strcasecmp($file_extension, $extension) == 0) {
            $is_valid_extension = true;
            break;
        }
    }
    if (!$is_valid_extension) {
        echo "{";
        echo        "error: 'Filtype not allowed!'\n";
        echo "}";
        exit(0);
    }
    /* checking filetype*/
switch(exif_imagetype($_FILES[$upload_name]['tmp_name'])) {
    case IMAGETYPE_GIF:
    case IMAGETYPE_JPEG:
    case IMAGETYPE_PNG:
        break;
    default:
        echo "{";
        echo        "error: 'This is no real image!'\n";
        echo "}";
        exit(0);
}

    /* file size check */
    $file_size = @filesize($_FILES[$upload_name]["tmp_name"]);
    if (!$file_size || $file_size > $max_file_size_in_bytes) {
        echo "{";
        echo        "error: 'Filesize exceeds the limit: 6MB'\n";
        echo "}";
        exit(0);
    }




    if(isset($_FILES[$upload_name]))
        if ($_FILES[$upload_name]["error"] > 0) {
            echo "Error: " . $_FILES["file"]["error"] . "<br />";
            } else  {
                $userfile = stripslashes($_FILES[$upload_name]['name']);
                $file_size = $_FILES[$upload_name]['size'];
                $file_temp = $_FILES[$upload_name]['tmp_name'];
                $file_type = $_FILES[$upload_name]["type"];
                $file_err = $_FILES[$upload_name]['error'];
                $file_name = $userfile;

                if(move_uploaded_file($file_temp, "images/profilePhoto/".$file_name)) {
                    echo "{";
                    echo        "msg: '".$file_name."'";
                    echo "}";
                }
            }
    break;

    case 'crop':
    if ($_SERVER['REQUEST_METHOD'] == 'POST')   {


        $jpeg_quality = 90;

        $src = "images/profilePhoto/".$_POST['fname'];
        $ext= pathinfo($src, PATHINFO_EXTENSION);


    if($ext == "jpg" OR $ext == "jpeg" OR $ext == "JPG"){
        $img_r = imagecreatefromjpeg($src); // <-- im getting out of memory error on this line

    }elseif($ext == "png" OR $ext == "PNG"){
        $img_r = imagecreatefrompng($src);
    }elseif($ext == "gif" OR $ext == "GIF"){
        $img_r = imagecreatefromgif($src);
    }

        if($_POST['fixed'] == 0) {
           $targ_w = $_POST['w'];
           $targ_h = $_POST['h'];
        }
        else {
            $targ_h = $_POST['sizeh']; 
            $targ_w = $_POST['sizew']; 
        }

        $dst_r = ImageCreateTrueColor( $targ_w, $targ_h );

        imagecopyresampled($dst_r,$img_r,0,0,$_POST['x'],$_POST['y'],
        $targ_w,$targ_h,$_POST['w'],$_POST['h']);
        imagedestroy($img_r); // free memory

    $path_thumbs = "images/profilePhoto/thumbs";
        $filename = $USER . ".jpg";
        $thumb_path = $path_thumbs . '/' . $filename;

        imagejpeg($dst_r,$thumb_path,$jpeg_quality);
        imagedestroy($dst_r); // free memory

        echo json_encode(array(
            'filename'=>$thumb_path
        ));
        unlink($src);       


    }   
    break;
}

我的主机仅支持GD lib裁剪图像,因此无法使用imagemagick。

正如我之前提到的,我的主机在64M上有一个memory_limit,无法设置

4 个答案:

答案 0 :(得分:4)

不幸的是,您将受到内存限制的限制。 GD库看起来像是有可怕的内存管理。我刚刚尝试加载尺寸为3951x2520&amp;的图像。我的脚本内存使用量从加载前的512KB增加到加载后的大约50MB(PHP 5.3.3,Windows 7 Home x64)。实际图像应该只占用大约28.49MB的内存,那么为什么GD的这个数量几乎翻了一倍呢?我不知道。

编辑:实际上看起来原因是因为GD将图像存储在内部GD2格式中,而这种格式不是内存效率。

Edit2 :看起来GD2格式实际上仅比实际的真彩色位图膨胀了约67%。令人惊讶的是,原始GD格式比原始图像本身或GD2占用更小的空间。我认为这是由于抖动造成的,这在输出上是显而易见的。我可以看到将文件加载到原始GD格式的唯一方法是首先使用它的图像函数(例如imagecreatefromjpeg)加载它,然后使用imagegd(不是imagegd2)保存它然后重新加载它与imagecreatefromgd一起。这不是很有效,肯定会发生抖动。

最终修改

我认为这比我之前的功能更好。你给它文件的文件名以及目标高度&amp;宽度和宽度如果你有足够的时间来执行调整大小,它将检查可用的内存并返回true或false。如果您只想知道需要多少内存,那么您可以将$传递给$ returnRequiredMem参数。

function checkMemAvailbleForResize($filename, $targetX, $targetY,$returnRequiredMem = false, $gdBloat = 1.68) {
    $maxMem = ((int) ini_get('memory_limit') * 1024) * 1024;
    $imageSizeInfo = getimagesize($filename);
    $srcGDBytes = ceil((($imageSizeInfo[0] * $imageSizeInfo[1]) * 3) * $gdBloat);
    $targetGDBytes = ceil((($targetX * $targetY) * 3) * $gdBloat);
    $totalMemRequired = $srcGDBytes + $targetGDBytes + memory_get_usage();
    if ($returnRequiredMem) return $srcGDBytes + $targetGDBytes;
    if ($totalMemRequired > $maxMem) return false;
    return true;
}

示例:

if (!checkMemAvailableForResize('path/to/file.jpg', 640,480)) die('Cannot resize!');

或:

$totalBytesNeeded = checkMemAvailableForResize('path/to/file.jpg',640,480,true);

此外,您可以调整$ gdBloat参数,以防68%太少或太多开销:

checkMemAvailableForResize('path/to/file.jpg',640,480,false, 1.69);

答案 1 :(得分:1)

请记住,虽然GD正在操作图像,但它并不是以压缩格式存储的。因此,GD需要与图像一起使用的内存量与其大小(宽度x高度)成正比,而您上传的图像可能是压缩的,因此在您自己的磁盘上可能要小得多。

例如,您可能正在上传一个1MB的文件,但该文件实际上是1024x1024像素,因此需要大约~4MB的内存才能加载GD - 或者如果它甚至更大(例如2048x2048),它会更多像16MB的内存等

答案 2 :(得分:0)

Filesize在jpeg上无关紧要,因为这些东西是压缩的。如果您使用此图像,它将作为位图存储在内存中,我认为这就是您的问题。

您可以尝试使用ImageMagick,因为它不需要像gd那样多的内存!

ImageMagick on php.net

答案 3 :(得分:0)

您应该在客户端浏览器上调整图像大小,而不是在服务器上。 这是用html5 canvas元素制作的。您可以编写自己的函数或使用插件。有一个很好的jquery插件可以做到这一点。

Blueimp jQuery File Upload