2011-06-30 23 views
5

多くのタスクを実行し、約21k回実行するスクリプトがあります。問題は各インデックスのために私はいくつかの異なることをしている、各インデックスは私たちのデータベース内の製品です、私はAPIからデータをつかんで、製品を保存して価格を更新しています。ほとんどすべてのメソッド呼び出しの前後にmemory_get_usage()に電話をかけているところがいくつかあります。私が持っている人は誰でもメモリを増やしているようです。他のものよりも多くをしているものも、それほど目立つものもありません。ForループのPHPメモリ使用量が増え続ける

ループの最後にすべての変数を設定解除しようとしているだけでなく、nullに設定しようとしましたが、メモリの制限が何回繰り返しても保持されます。

このメモリをクリアするためにできることはありますか?変数を設定解除するとメモリを解放すると考えられますが、そうは思われません。

編集: 私がこれを調査し始めた理由を忘れてしまったのは、サーバー上でメモリ制限エラーが発生していることです。それは常に同じポイントで起こるとは限らず、実行されるたびに起こることさえありません。だから私はそれを調べようとしたのです。

スクリプトの実行には約1時間かかりますが、何も起こっていない午前中に実行していますが、今はステージングサーバー上にしか存在しません。

私は、コードを投稿することができますが、PHPでのかなり大きな

<?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"; 
+0

コードを投稿しない限り、あなたを助けることはほとんど不可能です。 – Cfreak

+0

は私のコードで大きく更新されました –

答えて

5

増加メモリ使用量が通常です。変数を設定解除しても、それが直面していたメモリがただちに解放されるわけではなく、単に再利用可能なものとしてマークされます。ある時点で、PHPはガベージコレクタを実行する必要があると判断し、メモリが完全に解放されたときです。

実際に「メモリ不足」の致命的なエラーに遭遇していない限り、これは心配するものではありません。 PHPはOOMが起きないように最善を尽くしますが、変数を設定解除するたびに非常に高価なガベージコレクションの実行は行いません。それが起こっているならば、パフォーマンスは文字通り停止するでしょう。

+0

また、スクリプト/スレッドが完了した時点でメモリを解放する必要があります。そうしないと、PHPのガベージコレクションが処理されます。 – Brian

+1

申し訳ありませんが、私は私の投稿を更新すると言及を忘れてしまった、私はスクリプト全体のメモリの問題を出ている。常に起こるとは限らず、同じ場所で必ずしも起こるとは限りません。だからどこから来ているのかを知るために、使い方を知るための呼び出しを出し始めました。 –

+0

あなたはどのバージョンのPHPを使用していますか? 5.3にはガベージコレクタが改良されており、以前のバージョンでは多くのメモリリークが発生した循環参照が破損する可能性があります。私のローカルの –

0

あなたのコードを見ることなく、私の推測では、PHPのガベージコレクション(未使用メモリの解放)はスクリプトの実行に時間がかからないということです。

この点は問題ありません。あなたが何らかの記憶エラーを起こしていない限り、あなたは大丈夫でしょう。

+0

自分のコードで更新しました。はいエラーが発生しています。 –

関連する問題