【问题标题】:PHP: Handle memory & code low memory usagePHP:处理内存和代码低内存使用
【发布时间】:2010-11-12 08:28:32
【问题描述】:

是的,我遇到了 PHP 内存问题。我的主机提供最大。使用 64M 内存限制,并且不知何故当我上传 + 裁剪功能超过此内存时,我收到错误(但并非总是如此,取决于图像大小)

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

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

我尝试在 gd 中的任何函数之后执行 imagedestroy(),我不再使用,但这并没有影响它。虽然我只在案例裁剪中使用了GDfunctions

那么在上传案例时有什么可以释放我的记忆的吗?

或者一般来说如何释放 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。

正如我之前提到的,我的主机的 memory_limit 为 64M,无法设置

【问题讨论】:

    标签: php memory memory-management


    【解决方案1】:

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

    编辑:实际上看起来原因是因为 GD 以内部 GD2 格式存储图像,内存效率不高。

    Edit2:看起来 GD2 格式实际上只比实际的真彩色位图膨胀约 67%。令人惊讶的是,原始 GD 格式比原始图像本身或 GD2 占用的空间更小。我相信这是由于抖动,这在输出中很明显。我能看到将文件加载为原始 GD 格式的唯一方法是首先使用它的图像函数(例如 imagecreatefromjpeg)加载它,然后使用imagegd(不是imagegd2)保存它,然后用@987654323 重新加载它@。这不是很有效,而且肯定会出现抖动。

    最终编辑

    我觉得这个功能比我之前在下面的功能更好。你给它你的文件的文件名以及目标高度和宽度&它会检查可用内存,如果你有足够的空间来执行调整大小,它会返回真或假。如果您只想知道大约需要多少内存,那么您可以将 true 作为 $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);
    

    【讨论】:

    • 你好。我已经测试了您的脚本并成功收到此错误。我想知道您是如何设置尺寸限制的?(多少高度像素和宽度像素)。谢谢
    • / 图片可以有多大? 1024 像素 * 1024 像素?
    • 嗯,考虑总像素而不是实际尺寸会更好。示例:512x2048 等于 1048576 像素,但 1024x1024 也是如此。如果你想要 1024x1024,你可以设置一个硬限制,这可能会让你达到你的极限。该脚本应该更灵活,并且可以更好地计算到您的内存限制,而不是施加硬限制。第一行控制允许单个图像占用多少内存,您可以将 32 更改为 24 或 48,这将减少或增加图像允许占用的 RAM 量。
    • 这是因为我想告诉用户图像可以有多大。所以我只是通过最大通知他们。 1024x1024 ?
    • 您必须考虑 A) 您的脚本已经使用了多少内存 B) 未压缩的图像将占用多少内存 & C) 未压缩的重采样图像将占用多少内存.我的计算表明,如果您的脚本本身占用的空间小于 4MB,并且您正在调整为小于原始尺寸的尺寸,那么您可能会达到 2500x2500 作为最大分辨率。
    【解决方案2】:

    请记住,当 GD 处理图像时,它不会以压缩格式存储。因此,GD 处理图像所需的内存量与其大小(宽度 x 高度)成正比,而您上传的图像可能是压缩的,因此在您自己的磁盘上可能要小得多。

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

    【讨论】:

    • 嗨。谢谢,让我明白了!但是我怎样才能解决这个问题并降低使用率呢?
    • 我确定你已经尝试过 "ini_set(“memory_limit”,”1024M”); ? ;-)
    • 是的,我无法更改,因为我的最大值为 64M
    【解决方案3】:

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

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

    ImageMagick on php.net

    【讨论】:

      【解决方案4】:

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

      Blueimp jQuery File Upload

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-15
        • 2022-09-27
        • 1970-01-01
        • 1970-01-01
        • 2014-06-26
        • 1970-01-01
        • 2011-08-24
        • 1970-01-01
        相关资源
        最近更新 更多