মেমরি ফুটো নির্ণয় - অনুমোদিত # বাইটের মেমরির আকার শেষ


98

আমি ভয়ঙ্কর ত্রুটি-বার্তার মুখোমুখি হয়েছি, সম্ভবত-শ্রমসাধ্য প্রচেষ্টা দিয়ে, পিএইচপি স্মৃতিশক্তি হারিয়েছে:

123 লাইনে file.php- এ #### বাইটগুলি মজাদার মেমরির আকার (#### বাইট বরাদ্দ দেওয়ার চেষ্টা করা হয়েছে)

সীমা বাড়ানো

আপনি যদি জানেন যে আপনি কী করছেন এবং সীমাটি বাড়াতে চান মেমোরিটি দেখুন :

ini_set('memory_limit', '16M');
ini_set('memory_limit', -1); // no limit

সাবধান! আপনি কেবল লক্ষণটি সমাধান করছেন এবং সমস্যাটি নয়!

ফুটো নির্ণয়:

ত্রুটি বার্তা একটি লুপের সাথে থাকা একটি লাইনের দিকে ইঙ্গিত করে যা আমি বিশ্বাস করি যে মেমরি ফাঁস, বা অকারণে-জমে থাকা memory আমি memory_get_usage()প্রতিটি পুনরাবৃত্তির শেষে বিবৃতি মুদ্রণ করেছি এবং সীমাটি না পৌঁছানো পর্যন্ত ধীরে ধীরে সংখ্যাটি বৃদ্ধি পেতে দেখতে পাচ্ছি:

foreach ($users as $user) {
    $task = new Task;
    $task->run($user);
    unset($task); // Free the variable in an attempt to recover memory
    print memory_get_usage(true); // increases over time
}

এই প্রশ্নের প্রয়োজনে ধরে নেওয়া যাক কল্পনাযোগ্যভাবে সবচেয়ে খারাপ স্প্যাগটি কোডটি কোথাও $userবা কোথাও গ্লোবাল স্কোপে লুকিয়ে রয়েছে Task

কোন সরঞ্জামগুলি, পিএইচপি কৌশল বা ডিবাগিং ভুডো আমাকে সমস্যাটি খুঁজে পেতে এবং সমাধান করতে সহায়তা করতে পারে?


পিএস - আমি সম্প্রতি এই সঠিক ধরণের জিনিস নিয়ে একটি সমস্যায় পড়েছি। দুর্ভাগ্যক্রমে, আমি আরও জানতে পেরেছিলাম যে পিএইচপি একটি শিশু অবজেক্ট ধ্বংসের সমস্যা রয়েছে। আপনি যদি কোনও প্যারেন্ট অবজেক্টটি আনসেট করেন তবে তার চাইল্ড অবজেক্টগুলি মুক্ত হয় না। আমি নিশ্চিত হয়েছি যে আমি একটি সংশোধিত আনসেট ব্যবহার করেছি যাতে সমস্ত শিশু অবজেক্টগুলিতে একটি পুনরাবৃত্ত কল রয়েছে __ড্রাস্ট্রাক্ট এবং আরও। বিশদগুলি এখানে: পল- মি- জোনস / আর্কাইভস / ২62২২ : আমি এর মতো কিছু করছি: ফাংশন সুপার_উনসেট ($ আইটেম) {যদি (is_object ($ আইটেম) এবং& পদ্ধতি_এক্সেস্ট ($ আইটেম, "__ড্রাস্ট্রাক্ট")) {$ আইটেম -> __ ধ্বংস (); } আনসেট ($ আইটেম); }
জোশ

উত্তর:


48

পিএইচপি-তে কোনও আবর্জনা সংগ্রহকারী নেই। এটি মেমরি পরিচালনা করতে রেফারেন্স গণনা ব্যবহার করে। সুতরাং, মেমরি ফাঁসের সর্বাধিক সাধারণ উত্স হ'ল চক্রীয় রেফারেন্স এবং গ্লোবাল ভেরিয়েবল। আপনি যদি কোনও ফ্রেমওয়ার্ক ব্যবহার করেন তবে এটি সন্ধানের জন্য আপনার প্রচুর কোড ট্রল করতে হবে, আমি ভীত। সর্বাধিক সহজ উপকরণ হ'ল নির্বাচিতভাবে কলগুলি স্থাপন করা memory_get_usageএবং কোডটি যেখানে ফাঁস হয় সেখানে এটি সংকীর্ণ করা। কোডের ট্রেস তৈরি করতে আপনি xdebug ব্যবহার করতে পারেন। এক্সিকিউশন ট্রেস এবং সহ কোড চালান show_mem_delta


4
তবে দেখুন ... তৈরি হওয়া ট্রেস ফাইলগুলি দুর্দান্ত হবে। আমি প্রথমবার একটি জেনড ফ্রেমওয়ার্ক অ্যাপ্লিকেশনটিতে একটি এক্সডিবেগ ট্রেস চালিয়েছি এটি চালাতে বেশ দীর্ঘ সময় নিয়েছে এবং একটি বহু জিবি (কেবি বা এমবি নয় ... গিগাবাইট) আকারের ফাইল উত্পন্ন করেছে। শুধু এই সম্পর্কে সচেতন হতে হবে।
rg88

4
হ্যাঁ, এটি বেশ ভারী .. গিগাবাইট কিছুটা হলেও শোনায় - যদি না আপনার কাছে বড় স্ক্রিপ্ট থাকে। হয়তো কয়েক সারি প্রক্রিয়া করার চেষ্টা করুন (ফাঁস চিহ্নিত করার জন্য যথেষ্ট হওয়া উচিত)। এছাড়াও, প্রোডাকশন সার্ভারে xdebug এক্সটেনশন ইনস্টল করবেন না।
আফ্রোস্কেন

31
5.3 পিএইচপি আসলে একটি আবর্জনা সংগ্রহকারী আছে। অন্যদিকে, মেমোরি প্রোফাইলিং ফাংশনটি xdebug থেকে সরানো হয়েছে :(
ডাব্লিউডে

4
+1 ফাঁস পাওয়া গেল! চক্রীয় রেফারেন্স ছিল এমন একটি ক্লাস! একবার এই রেফারেন্সগুলি আনসেট করা () হয়ে গেলে, প্রত্যাশাগুলি হিসাবে আবর্জনা সংগ্রহ করা হয়েছিল! ধন্যবাদ! :)
রিনোগো

@rinogo সুতরাং কিভাবে আপনি এই ফাঁস সম্পর্কে জানতে পারেন? আপনি কী পদক্ষেপ নিয়েছেন তা ভাগ করে নিতে পারেন?
জনিকিউ

11

কোন স্ক্রিপ্টগুলি আমাদের সার্ভারে সর্বাধিক মেমরি ব্যবহার করছে তা সনাক্ত করতে আমরা এখানে একটি কৌশল ব্যবহার করেছি।

নীচে স্নিপেট একটি ফাইল এ সংরক্ষণ করুন, উদাহরণস্বরূপ /usr/local/lib/php/strangecode_log_memory_usage.inc.php:

<?php
function strangecode_log_memory_usage()
{
    $site = '' == getenv('SERVER_NAME') ? getenv('SCRIPT_FILENAME') : getenv('SERVER_NAME');
    $url = $_SERVER['PHP_SELF'];
    $current = memory_get_usage();
    $peak = memory_get_peak_usage();
    error_log("$site current: $current peak: $peak $url\n", 3, '/var/log/httpd/php_memory_log');
}
register_shutdown_function('strangecode_log_memory_usage');

নিম্নলিখিতটি httpd.conf এ যুক্ত করে এটি নিয়োগ করুন:

php_admin_value auto_prepend_file /usr/local/lib/php/strangecode_log_memory_usage.inc.php

তারপরে লগ ফাইলটি বিশ্লেষণ করুন /var/log/httpd/php_memory_log

touch /var/log/httpd/php_memory_log && chmod 666 /var/log/httpd/php_memory_logআপনার ওয়েব ব্যবহারকারী লগ ফাইলটিতে লিখতে পারে তার আগে আপনার প্রয়োজন হতে পারে ।


8

আমি একটি পুরানো স্ক্রিপ্টে একবার লক্ষ্য করেছি যে পিএইচপি আমার পূর্ববর্তী লুপের পরেও স্কোপ হিসাবে "হিসাবে" পরিবর্তনশীল বজায় রাখবে। উদাহরণ স্বরূপ,

foreach($users as $user){
  $user->doSomething();
}
var_dump($user); // would output the data from the last $user 

আমি নিশ্চিত নই যে ভবিষ্যতের পিএইচপি সংস্করণগুলি এটি স্থির করেছে বা না থেকে আমি এটি দেখেছি। যদি এটি হয় তবে আপনি লাইনের unset($user)পরে doSomething()এটিকে মেমরি থেকে সাফ করতে পারেন। ওয়াইএমএমভি


13
পিএইচপি সি / জাভা / ইত্যাদির মতো স্কোপ লুপ / ​​শর্তসাপেক্ষ নয়। লুপ / ​​শর্তসাপেক্ষে ঘোষিত যে কোনও কিছুই লুপ / ​​শর্তসাপেক্ষে (ডিজাইনের মাধ্যমে [?]) প্রস্থান করার পরেও সুযোগে রয়েছে। অন্যদিকে, পদ্ধতিগুলি / ফাংশনগুলি যেমনটি আপনি প্রত্যাশা করেন তেমনভাবে বাদ দেওয়া হয় - ফাংশন সম্পাদন শেষ হয়ে গেলে সবকিছুই প্রকাশিত হয়।
ফ্রাঙ্ক ফার্মার

আমি ধরে নিয়েছি যে নকশা দ্বারা। এর একটি সুবিধা হ'ল লুপের পরে আপনি পাওয়া সর্বশেষ আইটেমটি নিয়ে কাজ করতে পারেন, যেমন নির্দিষ্ট মানদণ্ডকে সন্তুষ্ট করে।
জোআচিম

আপনি unset()এটি করতে পারেন, তবে মনে রাখবেন যে অবজেক্টগুলির জন্য, আপনি যা করছেন তার সমস্ত পরিবর্তন হচ্ছে যেখানে আপনার ভেরিয়েবলটি নির্দেশ করছে - আপনি আসলে এটিকে স্মৃতি থেকে সরান নি। পিএইচপি মেমরিটি যেকোনভাবে সুযোগের বাইরে চলে যাওয়ার পরে স্বয়ংক্রিয়ভাবে মুক্ত করে দেবে, সুতরাং আরও ভাল সমাধান (এই উত্তরের শর্তে, ওপি-র প্রশ্ন নয়) ছোট ফাংশন ব্যবহার করা হয় যাতে তারা লুপ থেকে সেই পরিবর্তনশীলটির সাথে ঝুলিয়ে না রাখে too দীর্ঘ
রিচ কোর্ট

@ পেটাকল এর মেমোরি ফাঁসের সাথে কোনও সম্পর্ক নেই। এটি কেবল অ্যারে পয়েন্টার পরিবর্তন করা। এখানে একবার দেখুন: সংস্করণ 3 এ সংস্করণে prismnet.com/~mcmahon/ নোটস /arrays_and_pointers.html
ক্ষতি

7

পিএইচপিতে মেমরি ফাঁস হওয়ার সম্ভাব্য কয়েকটি পয়েন্ট রয়েছে:

  • পিএইচপি নিজেই
  • পিএইচপি এক্সটেনশন
  • আপনি ব্যবহার পিএইচপি লাইব্রেরি
  • আপনার পিএইচপি কোড

গভীর রিভার্স ইঞ্জিনিয়ারিং বা পিএইচপি উত্স কোড জ্ঞান ছাড়াই প্রথম 3 খুঁজে পাওয়া এবং এটি ঠিক করা বেশ কঠিন। শেষের জন্য আপনি মেমরি_জেট_উসেজ সহ মেমরি ফাঁস কোডের জন্য বাইনারি অনুসন্ধান ব্যবহার করতে পারেন


91
আপনার উত্তরটি প্রায় সাধারণ হিসাবে এটি অর্জন করতে পারত
ট্র্যাভিসো

4
এটি লজ্জাজনক যে এমনকি পিএইচপি 7.2 তারা মূল পিএইচপি মেমরির লিকগুলি ঠিক করতে সক্ষম হয় না। আপনি এটিতে দীর্ঘ চলমান প্রক্রিয়া চালাতে পারবেন না।
আফতাব নাভেদ

6

সাম্প্রতিক পরিস্থিতিতে আমি কী একত্রিত হই তার অধীনে আমি সম্প্রতি একটি অ্যাপ্লিকেশনটিতে এই সমস্যায় পড়েছি। পিএইচপি-র ক্লাইমে চালিত একটি স্ক্রিপ্ট যা অনেকগুলি পুনরাবৃত্তির উপরে চলে যায়। আমার স্ক্রিপ্ট বেশ কয়েকটি অন্তর্নিহিত লাইব্রেরির উপর নির্ভর করে। আমার সন্দেহ হয় যে একটি নির্দিষ্ট গ্রন্থাগারই এর কারণ এবং আমি এর ক্লাসগুলিতে উপযুক্ত ধ্বংসাত্মক পদ্ধতি যুক্ত করার চেষ্টা করে ব্যর্থ হয়ে কয়েক ঘন্টা ব্যয় করেছি। দীর্ঘ একটি ভিন্ন গ্রন্থাগারে রূপান্তর প্রক্রিয়ার মুখোমুখি (যা একই সমস্যা হতে পারে) আমি আমার ক্ষেত্রে সমস্যার জন্য একটি অপরিশোধিত কাজ নিয়ে এসেছি।

আমার পরিস্থিতিতে, একটি লিনাক্স ক্লিমে, আমি ব্যবহারকারীর রেকর্ডগুলির একটি গুচ্ছটি ঘুরে দেখছিলাম এবং তাদের প্রত্যেকের জন্য আমি তৈরি বেশ কয়েকটি ক্লাসের একটি নতুন উদাহরণ তৈরি করছি। আমি পিএইচপি এর এক্সিকিউট পদ্ধতি ব্যবহার করে ক্লাসগুলির নতুন উদাহরণগুলি তৈরি করার চেষ্টা করার সিদ্ধান্ত নিয়েছি যাতে সেই প্রক্রিয়াটি "নতুন থ্রেডে" চালিত হয়। আমি যা উল্লেখ করছি তার একটি সত্যিকারের মৌলিক নমুনা এখানে:

foreach ($ids as $id) {
   $lines=array();
   exec("php ./path/to/my/classes.php $id", $lines);
   foreach ($lines as $line) { echo $line."\n"; } //display some output
}

স্পষ্টতই এই পদ্ধতির সীমাবদ্ধতা রয়েছে এবং এর ঝুঁকির বিষয়ে একজনকে সচেতন হওয়া দরকার, কারণ খরগোশের কাজ তৈরি করা সহজ হবে তবে কিছু বিরল ক্ষেত্রে এটি একটি শক্ত জায়গাটি পেতে সহায়তা করতে পারে, যতক্ষণ না একটি ভাল সংশোধন করা যায় যেমনটি আমার ক্ষেত্রে রয়েছে।


6

আমি একই সমস্যা জুড়ে এসেছি, এবং আমার সমাধানটি ছিল নিয়মিত জন্য ফোরচ প্রতিস্থাপন। আমি সুনির্দিষ্ট সম্পর্কে নিশ্চিত নই, তবে দেখে মনে হচ্ছে ফোরচ বস্তুটির জন্য একটি অনুলিপি (বা কোনও কোনও নতুন রেফারেন্স) তৈরি করে। লুপের জন্য নিয়মিত ব্যবহার করে আপনি সরাসরি আইটেমটি অ্যাক্সেস করতে পারেন।


5

আমি আপনাকে পিএইচপি ম্যানুয়াল পরীক্ষা করতে বা gc_enable()আবর্জনা সংগ্রহ করার জন্য ফাংশন যুক্ত করার পরামর্শ দিচ্ছি ... এটিই আপনার কোডটি কীভাবে চালিত হয় তা মেমরির ফাঁস হয় না।

পিএস: পিএইচপি একটি আবর্জনা সংগ্রহকারী আছে gc_enable()যা কোনও যুক্তিই নেয় না।


3

আমি সম্প্রতি লক্ষ্য করেছি যে পিএইচপি 5.3 ল্যাম্বদা ফাংশনগুলি অপসারণ করা হলে অতিরিক্ত মেমরি ব্যবহার করে।

for ($i = 0; $i < 1000; $i++)
{
    //$log = new Log;
    $log = function() { return new Log; };
    //unset($log);
}

আমি নিশ্চিত না কেন, তবে ফাংশনটি অপসারণের পরেও প্রতিটি ল্যাম্বদা অতিরিক্ত 250 বাইট লাগবে বলে মনে হচ্ছে।


4
আমি একই বলতে যাচ্ছি। এটি 5.3.10 ( # 60139 ) হিসাবে ঠিক করা হয়েছে
ক্রিস্টোফার ইভস

@ ক্রিস্টোফারআইভেস, আপডেটের জন্য ধন্যবাদ! আপনি ঠিক বলেছেন, এটি এখন আর কোনও সমস্যা নয় তাই এখন তাদের পাগলের মতো ব্যবহার করা আমার ভয় করা উচিত নয়।
Xeoncross

2

যদি কোনও ফাংশনের পরে কেবলমাত্র জিসি করার বিষয়ে পিএইচপি সম্পর্কে আপনার বক্তব্যটি সত্য হয় তবে আপনি লুপের বিষয়বস্তুগুলিকে ওয়ার্কআউন্ড / পরীক্ষা হিসাবে ফাংশনের অভ্যন্তরে মোড়ানো করতে পারেন।


4
@ ডেভিডকুলম্যান আসলে আমার মনে হয় আমার উত্তরটি ভুল। সর্বোপরি, run()যাকে বলা হয় এটিও একটি ফাংশন, যার শেষে জিসির হওয়া উচিত।
বার্ট ভ্যান হিউকেলোম

2

আমার একটি বিশাল সমস্যা হ'ল ক্রিয়েট ফাংশনটি ব্যবহার করে । ল্যাম্বদা ফাংশনের মতো এটিও উত্পন্ন অস্থায়ী নামটিকে মেমরিতে ফেলে দেয়।

মেমরি ফাঁস হওয়ার আরেকটি কারণ (জেন্ড ফ্রেমওয়ার্কের ক্ষেত্রে) হ'ল জেন্ড_ডিবি_প্রফিলার। আপনি যদি জেন্ড ফ্রেমওয়ার্কের অধীনে স্ক্রিপ্টগুলি চালান তবে তা অক্ষম হয়েছে তা নিশ্চিত করুন। উদাহরণস্বরূপ আমি আমার অ্যাপ্লিকেশন.আইতে ফলোভিংটি পেয়েছিলাম:

resources.db.profiler.enabled    = true
resources.db.profiler.class      = Zend_Db_Profiler_Firebug

আনুমানিক 25.000 ক্যোয়ারী + এর আগে লোড প্রসেসিং চালানো, মেমরিটিকে একটি দুর্দান্ত 128 এমবি (আমার সর্বোচ্চ স্মৃতি সীমা) এনেছে brought

কেবল সেট করে:

resources.db.profiler.enabled    = false

এটি 20 এমবি এর নিচে রাখার জন্য যথেষ্ট ছিল

এবং এই স্ক্রিপ্টটি সিএলআইতে চলছিল, তবে এটি জেন্ড_এপ্লিকেশনটি ইনস্ট্যান্ট করছে এবং বুটস্ট্র্যাপ চালাচ্ছিল, সুতরাং এটি "বিকাশ" কনফিগার ব্যবহার করেছিল।

এটি xDebug প্রোফাইলিং সহ স্ক্রিপ্টটি চালাতে সত্যিই সহায়তা করেছিল


2

আমি এটি স্পষ্টভাবে উল্লিখিত দেখিনি , তবে এক্সডিবাগ সময় এবং মেমরির প্রোফাইলিং ( 2.6 হিসাবে ) একটি দুর্দান্ত কাজ করে । আপনি যে তথ্যটি জেনারেট করে তা নিতে পারেন এবং এটি আপনার পছন্দের গুই সামনের প্রান্তে ছেড়ে দিতে পারেন: ওয়েবগ্রান্ড (কেবলমাত্র সময়), কেচিচেগ্রিন্ড , কিচাচিগ্রিন্ড বা অন্যান্য এবং এটি আপনাকে বিভিন্ন বিপর্যয়ের উত্সগুলি খুঁজে পেতে দেয় এমন দরকারী কল ট্রি এবং গ্রাফ তৈরি করে ।

উদাহরণ (কিউচেগ্রিন্ডের): এখানে চিত্র বর্ণনা লিখুন


1

এই কথোপকথনে আমি কিছুটা দেরি করেছি তবে আমি জেন্ড ফ্রেমওয়ার্কের জন্য প্রাসঙ্গিক কিছু ভাগ করব।

পিএইচপি 5.2.9 দিয়ে বিকাশ করা একটি জেডএফ অ্যাপ্লিকেশন নিয়ে কাজ করার জন্য পিএইচপি 5.3.8 (পিএইচপিফার্ম ব্যবহার করে) ইনস্টল করার পরে আমার একটি মেমরি ফুটো সমস্যা ছিল। আমি যে মেমরি লিক এ্যাপাচি এর httpd.conf ফাইলের মধ্যে আলোড়ন সৃষ্টি করা হয়েছিল, আমার ভার্চুয়াল হোস্ট সংজ্ঞা, এটা বলছেন যেখানে আবিষ্কৃত SetEnv APPLICATION_ENV "development"। এই লাইনটি মন্তব্য করার পরে, মেমরি ফাঁস বন্ধ হয়ে গেছে। আমি আমার পিএইচপি স্ক্রিপ্টের (মূলত মূল সূচক। পিএফপি ফাইলটিতে ম্যানুয়ালি এটি সংজ্ঞায়িত করে) একটি ইনলাইন কাজ করার চেষ্টা করছি।


4
প্রশ্নটি বলছে সে সিএলআই-তে চলছে। তার মানে অ্যাপাচি প্রক্রিয়াটিতে মোটেই জড়িত নয়।
ম্যাক্সিমাম

4
@ ম্যাক্সিম ভাল পয়েন্ট, আমি এটি ধরতে ব্যর্থ হলাম, ধন্যবাদ। ওহ ভাল, আশা করি কিছু এলোমেলো গুগলার যেভাবেই আমি এখানে রেখেছি সেই নোটটি থেকে উপকার পাবেন, যেহেতু আমার সমস্যাটি সমাধান করার চেষ্টা করার সময় এই পৃষ্ঠাটি আমার জন্য উপস্থিত হয়েছিল।
ফ্রনজি

এই প্রশ্নের আমার উত্তরটি পরীক্ষা করুন, সম্ভবত এটি আপনার ক্ষেত্রেও ছিল।
অ্যান্ডি

আপনার অ্যাপ্লিকেশনটির পরিবেশের উপর নির্ভর করে বিভিন্ন কনফিগারেশন থাকা উচিত। "development"পরিবেশ সাধারণত লগিং & প্রোফাইলিং অন্যান্য পরিবেশের নাও থাকতে পারে যে একটি গুচ্ছ আছে। লাইন মন্তব্য শুধু যা সাধারণত আপনার আবেদন পরিবর্তে ডিফল্ট এনভায়রনমেন্ট ব্যবহার করেন, "production"বা "prod"। স্মৃতি ফুটো এখনও বিদ্যমান; এতে থাকা কোডটি কেবল সেই পরিবেশে কল করা হচ্ছে না।
মার্কো রায়

0

আমি এটি এখানে উল্লিখিত দেখিনি তবে একটি জিনিস যা সহায়ক হতে পারে তা হ'ল রেফকাউন্টটি দেখতে xdebug এবং xdebug_debug_zval ('ভেরিয়েবল নাম') ব্যবহার করা।

আমি পিএইচপি এক্সটেনশানটির উপায় পেতে একটি উদাহরণও সরবরাহ করতে পারি: জেন্ড সার্ভারের জেড-রে। যদি ডেটা সংগ্রহ সক্ষম করা থাকে তবে মেমরির ব্যবহার প্রতিটি পুনরাবৃত্তিতে ঠিক তেমনই বর্জ্য সংগ্রহ বন্ধ ছিল বলে বেলুন করবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.