1.9.2.0에서 Varien_Image_Adapter_Gd2의 새로운 소멸자와의 ImportExport 문제


23

누군가가 Magento CE 1.9.1.0과 1.9.2.0 사이에 도입 된 다음 코드가 무엇에 사용되는지 설명 할 수 있습니까?

class Varien_Image_Adapter_Gd2:

public function __construct()
{
    // Initialize shutdown function
    register_shutdown_function(array($this, 'destruct'));
}

/**
 * Destroy object image on shutdown
 */
public function destruct()
{
    @imagedestroy($this->_imageHandler);
}

이 두 기능이 추가 된 후 ImportExport 인터페이스를 사용하여 제품 갤러리 이미지 가져 오기가 작동을 멈췄습니다. 오류는 메모리 제한 때문입니다 (최대 열린 파일 크기 제한으로 나타남).

내 생각은 가져 오기로 열린 파일이 올바르게 닫히지 않는다는 것입니다.

또한 빈 destruct()함수 ( Mage_ImportExport_Model_Import_Adapter_Abstract)가 도입 되었지만 부모 논리와 일치하도록 확장해도 도움이되지 않습니다.

답변:


14

이미지 리소스를 파괴하려고 시도했지만 메모리 누수가 발생했습니다. 나는이 코드에 대한 타당한 이유를 생각할 수없고, 정직하지만, 무엇이 바뀌 었는지 설명 할 수있다 :

원래 imagedestroy()디스크립터에서 호출되었을 것입니다__destruct()

function __destruct()
{
    @imagedestroy($this->_imageHandler);
}

소멸자는 PHP 가비지 수집기가 사용되지 않는 객체 (즉, 더 이상 참조되지 않는 메모리의 객체)를 삭제할 때마다 호출됩니다.

이제는 종료 함수imagedestroy() 에서 호출되며 이것이 객체 의 메소드에 대한 콜백 이므로 끝까지 가비지 수집조차 할 수 없습니다. 이런 식으로 모든 이미지 리소스는 스크립트 실행이 완료 될 때까지 열려 있습니다.Varien_Image_Adapter_Gd2


설명 주셔서 감사합니다-이것이 내가 생각한 것입니다. 전체적으로이 도입 된 코드는 1.9.2에서 대부분의 수입품을 쓸모 없게 만듭니다. 내 눈에. 이것이 곧 해결되기를 바랍니다. 버그 보고서를 열 곳을 조언 해 주시겠습니까?
Achim Rosenhagen

6

내 Magento 1.9.2.0과 동일한 문제가 발생했습니다 ...

난 단지 변경 작업이 얻을 Varien_Image_Adapter_Gd2을 에서 /lib/Varien/Image/Adapter/Gd2.php다음과 같이 :

public function __construct()
{
    // Initialize shutdown function
    // register_shutdown_function(array($this, 'destruct'));
}

/**
 * Destroy object image on shutdown
 */
public function __destruct()
{
    @imagedestroy($this->_imageHandler);
}
  • register_shutdown_function으로 줄을 제거 하거나 주석 처리하십시오.
  • 변경 기능 이름의 파괴__destruct

memory_limit를 1G로 다시 설정했으며 (이전 32GB까지 올렸습니다) 이제 작동합니다 ...

이 프로젝트 는 modman 친화적 인 방식으로 상기 절차를 구현합니다. 작곡가와 함께 설치하기 만하면됩니다.


이것은 실제로 질문에 대답하지 않습니다. 다른 질문이 있으면 질문하기를 클릭하여 질문 할 수 있습니다 . 당신은 또한 충분한 명성을 얻은 후에이 질문에 더 많은 관심을 끌기 위해 현상금추가 할 수 있습니다 .
Rajeev K Tomy 1

그렇습니다.이 질문에 대한 답은 아니지만 임시 해결책이 필요하고 토론이 필요없는 사람들을 도울 것입니다.
dkr

가져 오는 동안 메모리 소비 문제가 해결되었습니다. 흥미롭게도, 마 젠토는 그들이 방출 한 것을 어떻게 테스트합니까?
klipach

이것은 수입 문제뿐만 아니라 해결합니다. 이렇게하면 모든 제품 이미지에 대해 캐시 및 크기가 조정 된 버전을 생성 / 재 작성하는 프로세스로 인한 메모리 소모를 해결할 수 있습니다. 이 "해킹"없이 제품에 png 이미지를 업로드하면 작동하지 않으며 많은 메모리 소진 오류가 발생합니다.
Simbus82

오늘 나는이 제안을 발견했다. 나는 그것을 구현했고 메모리 누수가 사라졌습니다. 그런 다음이 github.com/borasocom-team/magento-gd2-memoryleak 를 만들어 깨끗한 방식으로 설치했습니다.
Dr. Gianluigi Zane Zanettini

5

직렬화 해제와 관련된 보안 문제 해결의 일부였습니다. __destruct와 같은 마술 메서드에는 직렬화에 고유 한 문제가 있습니다.

우리는 파일 시스템에서 파일을 생성하기 위해 직렬화와 __destruct를 사용하는 익스플로잇을 제안했습니다.이 변경 (다른 장소에서 더 유사한 변경 사항이 표시됨)은 이것을 피하기 위해 수행되었습니다.

스크립트가 끝날 때까지 메모리 누수가 발생하거나 더 많은 메모리를 사용합니까?

/security/77549/is-php-unserialize-exploitable-without-any-interesting-methods


상황에 감사드립니다. 이 특정 변경은 특정 악용을 방지하거나 확실하게하기 위해 수행 되었습니까?
Fabian Schmengler

그리고 아니, 아마도 스크립트가 실제 메모리 누수가 아닌 더 많은 메모리를 소비하게 할 것입니다.
Fabian Schmengler

가져 오기 처리가 끝날 때까지 모든 이미지 파일을 열어두기 때문에 이미지를 가져올 때 특히 메모리 누수가 발생합니다. 이렇게하면 약 50 개의 제품 만 가져올 수 있습니다 (> 2k 이상의 가져 오기를 수행하기 전에). 8G RAM이있는 로컬 VM에서 테스트를 실행했으며 소스 파일은 모두 약 300KB입니다. 전체 가져 오기 동안 PHP rermains가 1k로 사용한 메모리를 변경하기 전에.
Achim Rosenhagen 18시 41 분

그것은 '메모리 누수'하지 않을 수도 있지만, 소비 ;-) 언덕 thraight 상승 - fschmengler은 맞다
아킴 Rosenhagen

1
조언에 대한 @Alex 감사합니다. 나는 그것을 반대로 패치했다. 이제 메모리 누수가 사라졌지 만 미래에는 해결책이 없습니다.
Arne

4

그래서 이미지 가져 오기 프로세스에서 메모리 사용 문제를 처리해야하는 "솔루션"을 포함하여 Magento에 버그를 제기했습니다.

해결책은 github의 https://github.com/sitewards/import_image_memory_leak_fix 에서 찾을 수 있지만 기본 아이디어는 다음과 같습니다.

이미지 프로세서에서 Mage_Catalog_Helper_Image::validateUploadFile실제로 destruct메소드를 호출하도록 수정했습니다 . 슬프게도 기본값 Varien_Image이 처리되지 않는 것처럼 보이므로 destruct자체 클래스를 추가해야했습니다.

<?php
/**
 * @category    Sitewards
 * @package     Sitewards_ImportImageMemoryLeakFix
 * @copyright   Copyright (c) Sitewards GmbH (http://www.sitewards.com/)
 */
class Sitewards_ImportImageMemoryLeakFix_Model_Destructable_Image extends Varien_Image
{
    /**
     * Constructor,
     * difference from original constructor - we register a destructor here.
     *
     * @param string $sFileName
     * @param Varien_Image_Adapter $oAdapter Default value is GD2
     */
    public function __construct($sFileName = null, $oAdapter = Varien_Image_Adapter::ADAPTER_GD2)
    {
        parent::__construct($sFileName, $oAdapter);

        // Initialize shutdown function
        register_shutdown_function(array($this, 'destruct'));
    }

    /**
     * Destroy object image on shutdown
     */
    public function destruct()
    {
        $oAdapter = $this->_getAdapter();
        if (method_exists($oAdapter, 'destruct')) {
            $oAdapter->destruct();
        } else {
            Mage::log('Image can not be destructed properly, adapter doesn\'t support the method.');
        }
    }
}

그런 다음 도우미를 다시 작성하십시오.

<?xml version="1.0"?>
<config>
    <modules>
        <Sitewards_ImportImageMemoryLeakFix>
            <version>0.1.0</version>
        </Sitewards_ImportImageMemoryLeakFix>
    </modules>
    <global>
        <models>
            <sitewards_importimagememoryleakfix>
                <class>Sitewards_ImportImageMemoryLeakFix_Model</class>
            </sitewards_importimagememoryleakfix>
        </models>
        <helpers>
            <catalog>
                <rewrite>
                    <image>Sitewards_ImportImageMemoryLeakFix_Helper_Catalog_Helper_Image</image>
                </rewrite>
            </catalog>
        </helpers>
    </global>
</config>

그리고 새로운 함수는 새로운 파괴 가능한 이미지 클래스를 호출합니다.

<?php
/**
 * @category    Sitewards
 * @package     Sitewards_ImportImageMemoryLeakFix
 * @copyright   Copyright (c) Sitewards GmbH (http://www.sitewards.com/)
 */
class Sitewards_ImportImageMemoryLeakFix_Helper_Catalog_Helper_Image extends Mage_Catalog_Helper_Image
{
    /**
     * Check - is this file an image
     *
     * Difference from original method - we destroy the image object here,
     * i.e. we are not wasting memory, without that fix product import with images
     * easily goes over 4Gb on memory with just couple hundreds of products.
     *
     * @param string $sFilePath
     *
     * @return bool
     * @throws Mage_Core_Exception
     */
    public function validateUploadFile($sFilePath) {
        if (!getimagesize($sFilePath)) {
            Mage::throwException($this->__('Disallowed file type.'));
        }

        /** @var Sitewards_ImportImageMemoryLeakFix_Model_Destructable_Image $oImageProcessor */
        $oImageProcessor = Mage::getModel('sitewards_importimagememoryleakfix/destructable_image', $sFilePath);
        $sMimeType       = $oImageProcessor->getMimeType();
        $oImageProcessor->destruct();

        return $sMimeType !== null;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.