Использование памяти PHP в цикле For продолжает расти - PullRequest
5 голосов
/ 30 июня 2011

У меня есть скрипт, который я запускаю, который выполняет много задач и проходит около 21 тыс. Раз.Проблема в том, что для каждого индекса я делаю несколько разных вещей, каждый индекс является продуктом в нашей базе данных, я обновляю цену, собирая данные из API, сохраняя продукт и так далее.У меня есть несколько областей, где я помещаю вызовы memory_get_usage() до и после почти каждого вызова метода, и все, что у меня есть, похоже, увеличивают память.Нет ни одного, который делает больше, чем другие, или его не так заметно.

Я пытался сбросить все свои переменные в нижней части цикла, а также пытался просто установить их на ноль, ноНеважно, какой лимит памяти просто увеличивается с каждой итерацией.

Есть ли что-то, что я могу сделать, чтобы очистить эту память, я думаю, что сброс переменных был бы свободным, но это не кажетсясделать это?

РЕДАКТИРОВАТЬ: я забыл упомянуть причину, почему я начал исследовать это то, что я получаю ошибки ограничения памяти на сервере.Это не всегда происходит в одной и той же точке или даже происходит каждый раз, когда запускается.Вот почему я пытался это расследовать.

Выполнение сценария занимает около часа, я запускаю его утром, когда больше ничего не происходит, и сейчас он все равно находится только на промежуточном сервере, так что на самом деле никто не поражает сервер.

Я могу опубликовать код, но он довольно большой

<?php


if( !function_exists('memory_get_usage') ){
    include('function.php');
}
echo "At the start we're using (in bytes): ",
     memory_get_usage() , "\n\n";

$path = realpath(dirname(__FILE__) . '/../../../../Mage.php');
require_once($path);
Mage::app();
require_once '/lib/ProductUpdate.php';
echo "Starting product update process \n\n";
$productUpdate = new ProductUpdate();
$dealerStoreId = 3;
$volumeDiscountGroupId = 4;
$retailGroupId = Mage_Customer_Model_Group::CUST_GROUP_ALL;
$wholesaleGroupId = 2;


echo "Grabbing all products \n\n";
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

// get the products from the InOrder stored procedure qty since datetime and don't pass a date to get all products, also pass the id of the cron job
$ioProducts = $productUpdate->getProductUpdateProducts('WEB2');
echo "---------------------------\n\n";
echo "Begin Updating Products \n\n";
echo "---------------------------\n\n";
$productCount = 0;
$productUpdate->saveScriptStarted(2);
echo "Before we go into the initial loop we are using (in bytes): ",
     memory_get_usage() , "\n\n";
foreach ($ioProducts as $ioProduct) {
    $updateProduct = false;
    $updateTierPrice = false;
    $sku = trim($ioProduct['inp_short_item_number']) . trim($ioProduct['isc_SIZE']) . trim($ioProduct['isc_COLOR']);
    echo "Checking item number " . $sku . " \n\n";
    echo "Before Loading Product " . $sku .  " we are using (in bytes): ",
     memory_get_usage() , "\n\n";
    $product = $productUpdate->getProduct();
    $productId = $product->getIdBySku($sku);
    echo "After Getting Id from sku " . $sku .  " we are using (in bytes): ",
     memory_get_usage() , "\n\n";
    if ($productId) {
        //$product = $productUpdate->getProduct()->load($productId);
        echo "After Loading Product " . $sku .  " we are using (in bytes): ",
            memory_get_usage() , "\n\n";
        echo "WE HAVE A PRODUCT!: " . $product->getName() . "\n\n";

        try {
            echo "Before Getting Additional Info from InOrder for Product " . $sku .  " we are using (in bytes): ",
            memory_get_usage() , "\n\n";

            // Since the product is same for parent products as it is for children you should just be able to get the price  of the parent and use that.
            $additionalInfo = $productUpdate->getItemDetails($ioProduct['inp_short_item_number'], 'WEB2');

            echo "After Getting Additional Info from InOrder for Product " . $sku .  " we are using (in bytes): ",
            memory_get_usage() , "\n\n";

            echo "Before Getting Extra Charges from InOrder for Product " . $sku .  " we are using (in bytes): ",
            memory_get_usage() , "\n\n";

            $oversizeCharge = $productUpdate->getExtraCharges($ioProduct['inp_short_item_number']);

            echo "After Getting Extra Charges from InOrder for Product " . $sku .  " we are using (in bytes): ",
            memory_get_usage() , "\n\n";
        } catch (Exception $e) {
            echo $e->getMessage() . "\n\n";
            continue;
        }

        if (is_array($additionalInfo) && count($additionalInfo) > 0) {
            if (isset($oversizeCharge[0]['Shipping Unit Charge']) && $product->getOversizeCharge() != $oversizeCharge[0]['Shipping Unit Charge']) {
                $product->setOversizeCharge($oversizeCharge[0]['Shipping Unit Charge']);
                $updateProduct = true;
                unset($oversizeCharge);
            }
            if ($product->getPrice() != $additionalInfo[0]['pri_current_price']) {
                $product->setPrice($additionalInfo[0]['pri_current_price']);
                $updateProduct = true;
                unset($additionalInfo);
            }
            echo "Before Setting Stock Status for Product " . $sku .  " we are using (in bytes): ",
            memory_get_usage() , "\n\n";

            $product = $productUpdate->setStockStatus($product, $ioProduct);

            echo "After Setting Stock Status for Product " . $sku .  " we are using (in bytes): ",
            memory_get_usage() , "\n\n";

            if ($product->getNeedsUpdate()) {
                $updateProduct = true;
            }

            if ($updateProduct) {
                try{
                    echo "Before Saving Product " . $sku .  " we are using (in bytes): ",
                    memory_get_usage() , "\n\n";

                   $productUpdate->saveProduct($product, $ioProduct);

                    echo "After Saving Product " . $sku .  " we are using (in bytes): ",
                    memory_get_usage() , "\n\n";
                }catch (Exception $e){
                    echo $e->getMessage() . "\n\n";
                    continue;
                }
            }


            // Go through  and do the same thing for the other 2 web classes to set pricing for the Dealer and Volume wholesale customers
            $updateProduct = false;
            try {
                echo "Before getting Tier Price info for " . $sku .  " we are using (in bytes): ",
                memory_get_usage() , "\n\n";

                $product = $productUpdate->getProduct()->setStoreId($dealerStoreId)->load($productId);
                $additionalInfo = $productUpdate->getItemDetails($ioProduct['inp_short_item_number'], 'WEB3');
                //$additionalTierInfo = $productUpdate->getItemDetails($ioProduct['inp_short_item_number'], 'WEB4');

                // Get Real Tier Prices based on Customer Type
                $retailPriceBreaks = $productUpdate->getItemPriceBreaks($ioProduct['inp_short_item_number'], Mage::getStoreConfig(Lancaster_InOrder_Helper_Data::XML_PATH_RETAIL_PRICE_LIST));
                $wholesalePriceBreaks = $productUpdate->getItemPriceBreaks($ioProduct['inp_short_item_number'], Mage::getStoreConfig(Lancaster_InOrder_Helper_Data::XML_PATH_WHOLESALE_PRICE_LIST));
                $volumeWholesalePriceBreaks = $productUpdate->getItemPriceBreaks($ioProduct['inp_short_item_number'], Mage::getStoreConfig(Lancaster_InOrder_Helper_Data::XML_PATH_VOLUME_WHOLESALE_PRICE_LIST));

                echo "After getting Tier Price infor for " . $sku .  " we are using (in bytes): ",
                memory_get_usage() , "\n\n";
            } catch (Exception $e) {
                echo $e->getMessage() . "\n\n";
                continue;
            }


            if ($product->getPrice() != $additionalInfo[0]['pri_current_price']) {
                $product->setPrice($additionalInfo[0]['pri_current_price']);
                $updateProduct = true;
            }

            //The only way to setup multiple price for one website is to set a tier price so we set it to a specific group and the dealer site then go through and set all the other real tier prices
            $tierPriceInfo = $product->getData('tier_price');
            if (!empty($tierPriceInfo)) {
                echo "Before looping through Tier Price infor for " . $sku .  " we are using (in bytes): ",
                memory_get_usage() , "\n\n";
                foreach ($tierPriceInfo as $tierPrice) {
                    if ($tierPrice["website_id"] == $dealerStoreId &&
                        $tierPrice["cust_group"] == $volumeDiscountGroupId &&
                        $tierPrice["price_qty"] == '1' &&
                        $tierPrice["price"] != $additionalTierInfo[0]['pri_current_price']) {
                        $updateTierPrice = true;
                    }
                    //todo need to do some refinement to the following, was rushed to put out the logic need to fix so it doesn't update everytime
                    // need to find if any of the tier prices do not match price as well if there is a price break in InOrder but not in Magento

                    if (!$updateTierPrice ) {

                        $updateRetail = isUpdateTierPrices($retailPriceBreaks, $tierPrice, $retailGroupId);
                        $updateWholesale = isUpdateTierPrices($wholesalePriceBreaks, $tierPrice, $wholesaleGroupId);
                        $updateVolWholesale = isUpdateTierPrices($volumeWholesalePriceBreaks, $tierPrice, $volumeDiscountGroupId);
                        if (
                            (count($retailPriceBreaks) > 0 && !$updateRetail['priceTierExists']) &&
                            (count($wholesalePriceBreaks) > 0 && !$updateWholesale['priceTierExists']) &&
                            (count($volumeWholesalePriceBreaks) > 0 && !$updateVolWholesale['priceTierExists'])) {
                             $updateTierPrice = true;
                        }

                        if(($updateRetail['updateTierPrice'] || $updateWholesale['updateTierPrice'] || $updateVolWholesale['updateTierPrice'])){
                            $updateTierPrice = true;
                        }
                    }
                }
                unset($tierPriceInfo);
                echo "After looping through Tier Price infor for " . $sku .  " we are using (in bytes): ",
                memory_get_usage() , "\n\n";
            }
            else {
                $updateTierPrice = true;
            }
            if ($updateTierPrice) {
                echo "Before setting whether we update Tier Price for " . $sku .  " we are using (in bytes): ",
                memory_get_usage() , "\n\n";
                //construct the tier price
                $website_id = Mage::getModel('core/store')->load($dealerStoreId)->getWebsiteId();
                $tierPrices = array(array(
                                        'website_id' => $website_id,
                                        'cust_group' => $volumeDiscountGroupId,
                                        'price_qty' => '1',
                                        'price' => $additionalTierInfo[0]['pri_current_price']
                                    ));

                updateTierPrices($retailPriceBreaks, $retailGroupId, $tierPrices);
                updateTierPrices($wholesalePriceBreaks, $wholesaleGroupId, $tierPrices);
                updateTierPrices($volumeWholesalePriceBreaks, $volumeDiscountGroupId, $tierPrices);

                $product->setData('tier_price', $tierPrices);
                $updateProduct = true;
                unset($website_id);
                echo "After setting whether we update Tier Price for " . $sku .  " we are using (in bytes): ",
                memory_get_usage() , "\n\n";
            }

            if ($updateProduct) {
                try{
                     echo "Before saving product for Tiered Pricing for " . $sku .  " we are using (in bytes): ",
                    memory_get_usage() , "\n\n";
                  // $productUpdate->saveProduct($product, $ioProduct);
                    echo "After saving product for Tiered Pricing for " . $sku .  " we are using (in bytes): ",
                    memory_get_usage() , "\n\n";
                }catch (Exception $e){
                    echo $e->getMessage() . "\n\n";
                    continue;
                }

            }
        }
    }
    $retailPriceBreaks = null;
    $wholesalePriceBreaks = null;
    $volumeWholesalePriceBreaks = null;
    $oversizeCharge = null;
    $additionalTierInfo = null;
    $additionalInfo = null;
    $product = null;
    $productCount++;
    echo $productCount . " Products have been proceessed \n\n";
}
echo "After running through all products we are using (in bytes): ",
                    memory_get_usage() , "\n\n";
echo "Peak memory usage for product update scrip (in bytes): ",
                    memory_get_peak_usage() , "\n\n";

Ответы [ 2 ]

5 голосов
/ 30 июня 2011

Увеличение использования памяти в PHP - это нормально.сброс переменной не сразу освобождает память, которую она занимала, он просто помечает ее как доступную для повторного использования.В какой-то момент PHP решит, что сборщик мусора должен быть запущен, и тогда память действительно будет освобождена.

Если вы на самом деле не сталкиваетесь с фатальными ошибками "не хватает памяти", это не о чем беспокоитьсяоколо.PHP делает все возможное, чтобы предотвратить возникновение OOM, но он не будет выполнять очень дорогие сборщики мусора каждый раз, когда вы отменяете переменную.Производительность буквально остановилась бы, если бы это произошло.

0 голосов
/ 30 июня 2011

Не видя вашего кода, я предполагаю, что сборка мусора в PHP (освобождение неиспользуемой памяти) не запускается в тот момент, когда запускается ваш скрипт.

Суть в том, что это поведение приемлемои ожидается.Пока вы не получаете ошибок памяти, с вами все будет в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...