2011-06-30 23 views
5

Tôi có một tập lệnh mà tôi chạy thực hiện nhiều tác vụ và trải qua khoảng 21k lần. Vấn đề là đối với mỗi chỉ mục tôi đang làm nhiều việc khác nhau, mỗi chỉ mục là một sản phẩm trong cơ sở dữ liệu của chúng tôi, tôi đang cập nhật giá bằng cách lấy dữ liệu từ API và lưu sản phẩm, v.v. Tôi có một số khu vực mà tôi đã đặt các cuộc gọi đến memory_get_usage() trước và sau gần như mọi cuộc gọi phương thức, và tất cả mọi người mà tôi làm dường như làm tăng bộ nhớ. Không có ai làm nhiều hơn những người khác hoặc không phải là đáng chú ý.Sử dụng bộ nhớ PHP trong vòng lặp for giữ ngày càng tăng

Tôi đã cố gắng bỏ đặt tất cả các biến của tôi ở cuối vòng lặp cũng như cố gắng chỉ đặt chúng thành rỗng, nhưng không có vấn đề gì giới hạn bộ nhớ chỉ tiếp tục tăng thông qua mỗi lần lặp.

Có bất kỳ điều gì tôi có thể làm để xóa bộ nhớ này, tôi nghĩ rằng việc tắt các biến được cho là để giải phóng bộ nhớ nhưng dường như không làm như vậy?

EDIT: Tôi quên đề cập đến lý do tại sao tôi bắt đầu điều tra điều này là tôi nhận được lỗi giới hạn bộ nhớ trên máy chủ. Nó không phải luôn luôn xảy ra tại cùng một điểm hoặc thậm chí xảy ra mỗi khi nó được chạy. Đó là lý do tại sao tôi đã cố gắng điều tra nó.

Tập lệnh mất khoảng một giờ để chạy, tôi chạy nó vào buổi sáng khi không có gì khác đang diễn ra và ngay bây giờ nó chỉ nằm trên máy chủ dàn dựng nên không có ai đánh máy chủ.

tôi có thể gửi mã nhưng khá lớn

<?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

Khá nhiều điều không thể giúp bạn trừ khi bạn đăng mã của mình. – Cfreak

+0

được cập nhật với mã của tôi, lớn của nó mặc dù –

Trả lời

5

Tăng sử dụng bộ nhớ của nó trong PHP là bình thường. unsetting một biến không ngay lập tức giải phóng bộ nhớ nó đang dùng, nó chỉ đơn giản là đánh dấu nó là có sẵn để được tái sử dụng. Tại một số điểm, PHP sẽ quyết định bộ thu gom rác sẽ được chạy, và đó là khi bộ nhớ thực sự được giải phóng.

Trừ khi bạn đang thực sự chạy vào "lỗi bộ nhớ" lỗi nghiêm trọng, điều này không có gì phải lo lắng. PHP làm hết sức mình để ngăn chặn OOM xảy ra, nhưng nó sẽ không làm việc thu gom rác rất đắt tiền chạy mỗi lần bạn bỏ đặt một biến. Hiệu suất theo nghĩa đen sẽ dừng lại nếu điều đó xảy ra.

+0

Cũng lưu ý bộ nhớ sẽ được phát hành khi kịch bản/chủ đề đã hoàn thành, nếu không thì Bộ sưu tập Rác của PHP sẽ xử lý nó. – Brian

+1

Xin lỗi tôi quên đề cập đến, mà tôi sẽ cập nhật bài đăng của mình, tôi sắp hết các vấn đề về bộ nhớ trong suốt tập lệnh. Nó không phải luôn luôn xảy ra và nó không phải luôn luôn xảy ra tại cùng một chỗ. Vì vậy, tôi bắt đầu đặt các cuộc gọi nhận được sử dụng để xem nó đến từ đâu và nhận thấy rằng nó đang tăng lên ở khắp mọi nơi. –

+0

Bạn đang sử dụng phiên bản php nào? 5.3 có bộ thu gom rác cải tiến có thể phá vỡ các tham chiếu vòng tròn, gây ra nhiều rò rỉ bộ nhớ trong các phiên bản trước. –

0

Nếu không nhìn thấy mã của bạn, tôi đoán là bộ sưu tập rác của PHP (giải phóng bộ nhớ không sử dụng) không chạy trong thời gian chạy tập lệnh của bạn.

Điểm của câu chuyện, hành vi này được chấp nhận và được mong đợi. Vì vậy, miễn là bạn không nhận được bất kỳ lỗi bộ nhớ, bạn nên được alright.

+0

Tôi đã cập nhật mã của mình và vâng tôi gặp lỗi –

Các vấn đề liên quan