Проблема ImportExport з новим деструктором Varien_Image_Adapter_Gd2 в 1.9.2.0


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. в моїх очах. Сподіваюся, це скоро буде виправлено. Будь-яка порада, де відкрити звіт про помилку?
Ахім Розенхаген

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 на __destruct

Я встановив memory_limit назад до 1G (раніше я піднімав до 32 ГБ), а тепер він працює ...

Цей проект реалізує згадану процедуру модним чином. Просто встановіть його разом із композитором, і ви готові йти.


Це насправді не відповідає на питання. Якщо у вас інше питання, ви можете задати його, натиснувши Задати питання . Ви також можете додати щедрості, щоб привернути більше уваги до цього питання, як тільки у вас буде достатня репутація .
Радєєв К Томі

Так, це не дає відповіді на питання, але допоможе людям, які потребують тимчасового рішення та без обговорення
впр

виправлена ​​проблема зі споживанням пам'яті під час імпорту. Цікаво, чи тестує Magento якось те, що вони випускають?
кліпач

Це вирішує не лише проблему імпорту. Це вирішує об'єм великої пам'яті за допомогою процесу, який створює / відтворює кеш і зміни розмірів версій для зображень для всіх продуктів. Якщо я завантажую PNG зображення у свої продукти, без цього "зламу" я не можу працювати, і я отримую багато помилок, виснажених пам'яттю.
Simbus82

Сьогодні я знайшов цю пропозицію. Я реалізував це, і витоку пам'яті вже немає. Потім я створив цей github.com/borasocom-team/magento-gd2-memoryleak, щоб встановити його чистим способом.
Доктор Джанлуїджі Зейн Занеттіні

5

Це було частиною виправлення проблем безпеки із несеріалізацією. Магічні методи, такі як __destruct, мають властиві проблеми серіалізації.

Ми бачили запропоновані подвиги, які використовували серіалізацію та __destruct для створення файлів у файловій системі - і ця зміна (ви побачите більше подібних змін в інших місцях) була зроблена, щоб цього уникнути.

Це спричиняє витік пам'яті або просто використовує більше пам'яті, поки сценарій не закінчиться?

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


Дякуємо за контекст. Чи було зроблено цю конкретну зміну для запобігання конкретного подвигу чи просто для впевненості?
Фабіан Шменглер

І ні, це, мабуть, просто змушує сценарій споживати більше пам’яті, а не справжню витік пам’яті
Фабіан Шменглер

Це спричиняє величезну витік пам'яті, особливо під час імпорту зображень, оскільки вона буде тримати всі файли зображень відкритими до кінця обробки імпорту. Таким чином ми можемо імпортувати лише близько 50 товарів (коли раніше ми не зможемо імпортувати> 2 к). Я провів свій тест на локальній VM з 8G оперативної пам’яті, а вихідні файли - приблизно 300 Кб. Перед зміною використовуваної пам'яті PHP залишається на 1 к протягом всього імпорту.
Ахім Розенхаген

fschmengler має рацію - це може бути не «витік пам’яті», але споживання піднімається на гору ;-)
Ахім Розенхаген,

1
@ Алекс дякую за пораду. Я зворотно заклеював це. Тепер витік пам’яті вже немає, але рішення на майбутнє немає.
Арне

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;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.