एक चर की स्मृति पदचिह्न (आकार) का निर्धारण कैसे करें?


102

क्या PHP (या PHP एक्सटेंशन) में कोई फ़ंक्शन है यह जानने के लिए कि किसी दिए गए वेरिएबल में कितनी मेमोरी है? sizeofबस मुझे तत्वों / गुणों की संख्या बताता है।

memory_get_usageइसमें मदद करता है कि यह मुझे पूरी स्क्रिप्ट द्वारा उपयोग की जाने वाली मेमोरी का आकार देता है । क्या एक एकल चर के लिए ऐसा करने का कोई तरीका है?

ध्यान दें कि यह एक विकास मशीन पर है, इसलिए एक्सटेंशन या डिबग टूल लोड करना संभव है।


संपादित - यह 5 साल बाद है, और कुछ समस्याएं अभी भी कुछ हद तक अनसुलझी हैं :(
पिस्कवर ने

जवाबों:


46

आपको संभवतः मेमोरी प्रोफाइलर की आवश्यकता है। मैंने एसओ को जानकारी दी है, लेकिन मैंने कुछ महत्वपूर्ण चीज़ों की नकल की है जो आपकी भी मदद कर सकती हैं।

जैसा कि आप शायद जानते हैं, Xdebug ने 2. * संस्करण के बाद से मेमोरी प्रोफाइलिंग समर्थन को गिरा दिया। कृपया यहां "हटाए गए कार्यों" स्ट्रिंग की खोज करें: http://www.xdebug.org/updates.php

निकाले गए कार्य

मेमोरी प्रोफाइलिंग के लिए हटाए गए समर्थन को ठीक से काम नहीं किया।

अन्य प्रोफाइलर विकल्प

php-स्मृति-प्रोफाइलर

https://github.com/arnaud-lb/php-memory-profiler । इसे मैंने अपने Ubuntu सर्वर पर सक्षम करने के लिए किया है:

sudo apt-get install libjudy-dev libjudydebian1
sudo pecl install memprof
echo "extension=memprof.so" > /etc/php5/mods-available/memprof.ini
sudo php5enmod memprof
service apache2 restart

और फिर मेरे कोड में:

<?php
memprof_enable();
// do your stuff
memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));

अंत में KCachegrind केcallgrind.out साथ फाइल खोलें

Google gperftools का उपयोग करना (अनुशंसित!)

सबसे पहले यहाँ नवीनतम पैकेज डाउनलोड करके Google gperftools स्थापित करें: https://code.google.com/p/gperftools/

फिर हमेशा की तरह:

sudo apt-get update
sudo apt-get install libunwind-dev -y
./configure
make
make install

अब आपके कोड में:

memprof_enable();

// do your magic

memprof_dump_pprof(fopen("/tmp/profile.heap", "w"));

फिर अपना टर्मिनल खोलें और लॉन्च करें:

pprof --web /tmp/profile.heap

नीचे दिखाए गए जैसे कुछ के साथ आपके मौजूदा ब्राउज़र सत्र में pprof एक नई विंडो बनाएगा:

PHP मेमोरी प्रोफाइलिंग के साथ मेम्प्रिफ़ और gperftools

Xhprof + Xhgui (cpu और मेमोरी दोनों को प्रोफाइल करने के लिए मेरी राय में सबसे अच्छा)

Xhprof और Xhgui के साथ यदि आप इस समय आपकी समस्या है तो आप CPU उपयोग को भी या केवल मेमोरी उपयोग को प्रोफाइल कर सकते हैं। यह एक बहुत ही संपूर्ण समाधान है, यह आपको पूर्ण नियंत्रण देता है और लॉग को मोंगो या फाइलसिस्टम पर लिखा जा सकता है।

अधिक जानकारी के लिए यहां देखें

तंबाकू से होने वाली बीमारी

Blackfire SensioLabs द्वारा एक PHP प्रोफाइलर है, सिम्फनी 2 लोग https://blackfire.io/

यदि आप अपने वर्चुअल मशीन को सेट करने के लिए प्यूपेट का उपयोग करते हैं, तो आपको यह जानकर खुशी होगी कि यह समर्थित है ;-)

Xdebug और ट्रेसिंग मेमोरी उपयोग

XDEBUG2 PHP के लिए एक विस्तार है। Xdebug आपको सभी फ़ंक्शन कॉल लॉग करने की अनुमति देता है, जिसमें विभिन्न स्वरूपों में फ़ाइल में मान और रिटर्न मान शामिल हैं। तीन आउटपुट स्वरूप हैं। एक का मतलब मानव पठनीय ट्रेस के रूप में है, एक और कंप्यूटर प्रोग्राम के लिए अधिक अनुकूल है क्योंकि यह पार्स करना आसान है, और अंतिम एक ट्रेस को प्रारूपित करने के लिए HTML का उपयोग करता है। आप सेटिंग के साथ दो अलग-अलग प्रारूपों के बीच स्विच कर सकते हैं। एक उदाहरण यहाँ उपलब्ध होगा

forp

forp सरल, गैर घुसपैठ, उत्पादन उन्मुख, PHP प्रोफाइलर। कुछ विशेषताएं हैं:

  • प्रत्येक कार्य के लिए समय और आवंटित स्मृति का मापन

  • सि पि यु का उपयोग

  • फ़ंक्शन कॉल की फ़ाइल और लाइन नंबर

  • Google के ट्रेस इवेंट प्रारूप के रूप में आउटपुट

  • कार्यों का कैप्शन

  • कार्यों का समूहन

  • कार्य के उपनाम (अनाम कार्यों के लिए उपयोगी)

DBG

DBG एक पूर्ण विशेषताओं वाला php डीबगर है, एक इंटरैक्टिव टूल जो आपको php स्क्रिप्ट डीबग करने में मदद करता है। यह एक उत्पादन और / या विकास वेब सर्वर पर काम करता है और आपको एक आईडीई या कंसोल से अपनी लिपियों को स्थानीय या दूरस्थ रूप से डीबग करने की अनुमति देता है, और इसकी विशेषताएं हैं:

  • दूरस्थ और स्थानीय डिबगिंग

  • स्पष्ट और निहित सक्रियण

  • कॉल स्टैक, फ़ंक्शन कॉल सहित, गतिशील और स्थिर विधि कॉल, उनके मापदंडों के साथ

  • इसी (नेस्टेड) ​​स्थानों में चर का मूल्यांकन करने की क्षमता के साथ कॉल स्टैक के माध्यम से नेविगेशन

  • चरण / चरण बाहर / चरण से अधिक / कर्सर कार्यक्षमता के लिए चलाएँ

  • सशर्त विराम बिंदु

  • वैश्विक विराम बिंदु

  • त्रुटियों और चेतावनियों के लिए लॉगिंग

  • समानांतर डिबगिंग के लिए एक साथ कई सत्र

  • GUI और CLI फ्रंट-एंड के लिए समर्थन

  • IPv6 और IPv4 नेटवर्क ने समर्थन किया

  • डीबगर द्वारा स्थानांतरित सभी डेटा वैकल्पिक रूप से एसएसएल के साथ संरक्षित किए जा सकते हैं


2
बात यह है कि वास्तव में जानकारी के लिए मैं देख रहा था, धन्यवाद।
पिस्कॉर ने इमारत

93

एक एकल चर की मेमोरी उपयोग प्राप्त करने का कोई सीधा तरीका नहीं है, लेकिन जैसा कि गॉर्डन ने सुझाव दिया है, आप उपयोग कर सकते हैं memory_get_usage। आवंटित की गई मेमोरी की कुल राशि वापस आ जाएगी, इसलिए आप एकल चर का उपयोग करने से पहले और बाद में एक वर्कअराउंड और माप उपयोग का उपयोग कर सकते हैं। यह थोड़ा हैकरी है, लेकिन यह काम करना चाहिए।

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;

ध्यान दें कि यह किसी भी तरह से एक विश्वसनीय तरीका नहीं है, आप यह सुनिश्चित नहीं कर सकते हैं कि चर को असाइन करते समय मेमोरी में कुछ भी नहीं छूता है, इसलिए इसका उपयोग केवल एक सन्निकटन के रूप में किया जाना चाहिए।

आप वास्तव में फ़ंक्शन के अंदर वेरिएबल की एक प्रति बनाकर और उपयोग की गई मेमोरी को मापकर उसे किसी फ़ंक्शन में बदल सकते हैं। यह परीक्षण नहीं किया गया है, लेकिन सिद्धांत रूप में, मुझे इसमें कुछ भी गलत नहीं दिखता है:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $tmp = unserialize(serialize($var));
    return memory_get_usage() - $start_memory;
}

14
$tmp = $varउथली प्रति बनाएंगे। यह अधिक मेमोरी आवंटित नहीं करेगा जब तक $ tmp को संशोधित नहीं किया जाता है।
गॉर्डन

@Gordon, तुम सही हो, मैं थोड़े उस बिंदु को नजरअंदाज कर दिया। जैसा कि मैं इसके प्रकार या आकार को बदलने के बिना चर को संशोधित करने का एक उचित तरीका नहीं समझ सकता, मैं इसे छोड़ दूँगा। शायद कोई व्यक्ति एक उचित विचार के साथ आ सकता है :)
तातु उलेमेन

7
कैसे के बारे में $tmp = unserialize(serialize($var)); यह ऊपर Aistina के दृष्टिकोण को संयोजित करेगा।
गॉर्डन

3
इसके अलावा, चूंकि $varपहले से ही उथली प्रतिलिपि या फ़ंक्शन के लिए क्या पारित किया गया था, का संदर्भ, आपको ज़रूरत नहीं है $tmp, लेकिन पुन: असाइन कर सकते हैं $var। यह आंतरिक संदर्भ को इससे बचाता $tmpहै $var
गॉर्डन

वहाँ से कुछ और सुरुचिपूर्ण तरीका $tmpनहीं है $var?
टॉम ज़ातो -

24

नहीं वहाँ नहीं है। लेकिन आप एक अनुमान के लिए परिणाम की serialize($var)जांच कर सकते हैं strlen


यह एक बेहतर दृष्टिकोण है, क्योंकि यह संपूर्ण जीसी चीज से बचा जाता है।
ग्‍लेनो

12
यह एक भयानक सन्निकटन है। PHP में एक सरणी में प्रत्येक आइटम ~ 80 बाइट्स है, फिर strlen(serialize(array(1,2,3)))भी 30 है।
gsnedders

2
@ आइस्टिना, -1। आप गलत बात को माप रहे हैं। चर और क्रमबद्ध चर दो पूरी तरह से अलग चीजें हैं, और पूरी तरह से अलग परिणाम देंगे।
पचेरियर

1
इतना ही नहीं, लेकिन यह कुछ गैर-धारावाहिक डेटा संरचनाओं पर पूरी तरह से विफल हो जाएगा , जैसे परिपत्र संदर्भ।
डस्कवफ़-एक्टिव-

20

तातु उलेमेन के जवाब में:

यह ध्यान दिया जाना चाहिए, कि $start_memoryखुद स्मृति ( PHP_INT_SIZE * 8) ले जाएगा ।

तो पूरा कार्य बनना चाहिए:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $var = unserialize(serialize($var));
    return memory_get_usage() - $start_memory - PHP_INT_SIZE * 8;
}

इसे एक अतिरिक्त उत्तर के रूप में जोड़ने के लिए क्षमा करें, लेकिन मैं अभी तक एक उत्तर पर टिप्पणी नहीं कर सकता।

अद्यतन: * The निश्चित नहीं है। यह जाहिरा तौर पर php संस्करण पर और संभवतः 64/32 बिट पर निर्भर कर सकता है।


4
क्या तुम समझा सकते हो क्यों * 8? धन्यवाद!
srasrasdetandil

@sierrasdetandil ऐसा लगता है कि $ start_memory ऊपर नहीं ले करता है केवल PHP_INT_SIZEबाइट्स, लेकिन PHP_INT_SIZE*8। आप कोशिश कर सकते हैं कि इस फ़ंक्शन को कॉल करके, यह 0:function sizeofvar() { $start_memory = memory_get_usage(); return memory_get_usage() - $start_memory - PHP_INT_SIZE*8; }
पैरा

8निरंतर नहीं लगता है। मेरी देव प्रणाली (PHP 5.6.19) पर आपकी टिप्पणी के बाद, यह वापस आ गया -16। साथ ही, दिलचस्प रूप से php -a, फ़ंक्शन की दो पंक्तियों को कॉल करने से विभिन्न भिन्न मूल्य मिलते हैं।
पॉल डेलरे

@PaDDelRe हाँ, शायद यह इस तरह के सामान के संस्करण / 64 बिट पर निर्भर है।
पैरा

अब घातक त्रुटि unserialize () कॉल पर होती है। वह कोई मदद नहीं है! यदि कोई चर इतना बड़ा है तो वह मेमोरी से बाहर चला जाता है, उस चर पर एक फ़ंक्शन को कॉल करने से और भी अधिक मेमोरी का उपयोग होगा। :(
जॉन ktejik

4

देख:

  • memory_get_usage() - PHP को आवंटित मेमोरी की मात्रा लौटाता है
  • memory_get_peak_usage() - PHP द्वारा आवंटित मेमोरी के शिखर को लौटाता है

ध्यान दें कि यह आपको किसी विशिष्ट चर का मेमोरी उपयोग नहीं देगा। लेकिन आप वेरिएबल को असाइन करने से पहले और बाद में इन फ़ंक्शन पर कॉल कर सकते हैं और फिर मानों की तुलना कर सकते हैं। यह आपको इस्तेमाल की गई मेमोरी का एक विचार देना चाहिए।

आप पीईसीएल एक्सटेंशन मेमट्रैक पर भी एक नज़र डाल सकते हैं , हालांकि प्रलेखन में थोड़ी कमी है, अगर नहीं कहना है, तो वस्तुतः गैर-मौजूद है।


हाँ। इसका उपयोग अप्रत्यक्ष रूप से प्रश्न का उत्तर देने के लिए किया जा सकता है।
नोटिनिस्ट

3

आप कॉलबैक रिटर्न मान पर मेमोरी अंतर की गणना करने का विकल्प चुन सकते हैं। यह PHP 5.3+ में अधिक सुंदर समाधान उपलब्ध है।

function calculateFootprint($callback) {
    $startMemory = memory_get_usage();
    $result = call_user_func($callback);
    return memory_get_usage() - $startMemory;
}

$memoryFootprint = calculateFootprint(
    function() {
        return range(1, 1000000);
    }
);

echo ($memoryFootprint / (1024 * 1024)) . ' MB' . PHP_EOL;

3

आप किसी चर के सटीक चरण-चिह्न की गणना नहीं कर सकते क्योंकि दो चर स्मृति में एक ही आवंटित स्थान साझा कर सकते हैं

चलो दो सरणियों के बीच स्मृति साझा करने का प्रयास करते हैं, हम देखते हैं कि दूसरे सरणी को आवंटित करने में पहले वाले की स्मृति का आधा हिस्सा खर्च होता है। जब हम पहले वाले को परेशान करते हैं, तो लगभग सभी मेमोरी का उपयोग दूसरे द्वारा किया जाता है।

echo memory_get_usage()."\n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."\n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."\n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."\n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."\n"; // <-- 433200 (-11032)

इसलिए हम दूसरे एरे की तुलना में आधी मेमोरी का उपयोग नहीं कर सकते, क्योंकि जब हम पहले वाले को परेशान करते हैं तो यह गलत हो जाता है।

पीएचपी में मेमोरी कैसे आवंटित की जाती है और किस उपयोग के लिए उपयोग किया जाता है, इस बारे में पूरी जानकारी के लिए, मैं आपको निम्नलिखित लेख पढ़ने का सुझाव देता हूं: वास्तव में पीएचपी सरणियाँ (और मूल्य) कितनी बड़ी हैं? (संकेत: बड़ा!)

संदर्भ गिनती मूल बातें पीएचपी दस्तावेज में भी स्मृति उपयोग के बारे में जानकारी का एक बहुत कुछ है, और संदर्भ साझा डेटा खंड के लिए गिनती।

यहाँ उजागर विभिन्न समाधान सन्निकटन के लिए अच्छे हैं लेकिन कोई भी PHP मेमोरी के सूक्ष्म प्रबंधन को नहीं संभाल सकता है।

  1. नव आवंटित स्थान की गणना

यदि आप असाइनमेंट के बाद नया आवंटित स्थान चाहते हैं, तो आपको memory_get_usage()आवंटन से पहले और बाद में उपयोग करना होगा, क्योंकि कॉपी के साथ इसका उपयोग करने से आपको वास्तविकता का एक गलत दृष्टिकोण मिलता है।

// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();

echo memory_get_usage()."\n";
$c=range(1,100);
echo memory_get_usage()."\n";

याद रखें कि यदि आप पहले के परिणाम को स्टोर करना चाहते हैं memory_get_usage(), तो चर को पहले से ही पहले से मौजूद memory_get_usage()होना चाहिए, और एक और पिछली बार बुलाया जाना चाहिए, और हर दूसरे फ़ंक्शन को भी।

यदि आप उपरोक्त उदाहरण में प्रतिध्वनित करना चाहते हैं, तो आउटपुट बफर को खोलने के लिए आवश्यक लेखांकन मेमोरी से बचने के लिए अपने आउटपुट बफर को पहले से ही खोलना होगा।

  1. आवश्यक स्थान की गणना

यदि आप किसी चर की प्रतिलिपि को संग्रहीत करने के लिए आवश्यक स्थान की गणना करने के लिए फ़ंक्शन पर भरोसा करना चाहते हैं, तो निम्न कोड विभिन्न अनुकूलन का ध्यान रखता है:

<?php
function getMemorySize($value) {
    // existing variable with integer value so that the next line
    // does not add memory consumption when initiating $start variable
    $start=1;
    $start=memory_get_usage();
    // json functions return less bytes consumptions than serialize
    $tmp=json_decode(json_encode($value));
    return memory_get_usage() - $start;
}

// open the output buffer, and calls the function one first time
echo ".\n";
getMemorySize(NULL);

// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
    // call the function name once 
    range(1,1);

    // we will compare the two values (see comment above about initialization of $start)
    $start=1;
    $start=memory_get_usage();
    $c=range(1,100);
    echo memory_get_usage()-$start."\n";
    echo getMemorySize($c)."\n";
}
test();

// same result, this works fine.
// 11044
// 11044

ध्यान दें कि चर नाम का आकार आवंटित मेमोरी में मायने रखता है।

  1. अपना कोड जांचें !!

एक चर का एक मूल आकार है जिसे PHP स्रोत कोड में उपयोग किए गए आंतरिक सी संरचना द्वारा परिभाषित किया गया है। यह आकार संख्याओं के मामले में उतार-चढ़ाव नहीं करता है। स्ट्रिंग्स के लिए, यह स्ट्रिंग की लंबाई को जोड़ देगा।

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value */
    zend_object_value obj;
} zvalue_value;

यदि हम चर नाम की गणना को ध्यान में नहीं रखते हैं, तो हम पहले से ही जानते हैं कि चर कितना उपयोग करता है (संख्या और तार के मामले में):

संख्या के मामले में 44 बाइट्स

तार के मामले में + 24 बाइट्स

स्ट्रिंग की लंबाई (अंतिम एनयूएल चरित्र सहित)

(वे संख्याएँ PHP संस्करण के आधार पर बदल सकती हैं)

मेमोरी एलाइनमेंट के कारण आपको कई 4 बाइट्स तक राउंड करना होगा। यदि वैरिएबल वैश्विक स्थान पर है (फ़ंक्शन के अंदर नहीं), तो यह 64 और बाइट्स भी आवंटित करेगा।

इसलिए यदि आप इस पृष्ठ के अंदर किसी एक कोड का उपयोग करना चाहते हैं, तो आपको यह जांचना होगा कि कुछ सरल परीक्षण मामलों (स्ट्रिंग्स या संख्याओं) का उपयोग करने वाला परिणाम इस पोस्ट के हर एक संकेत ($ _GLOBAL सरणी) में उन आंकड़ों को ध्यान में रखते हुए मेल खाता है, पहला फ़ंक्शन कॉल, आउटपुट बफर, ...)


1
... और वह इससे पहले कि हम इन्टर्नल में आएँ zvalue, is_refऔर कॉपी-ऑन-राइट करें। धन्यवाद।
पिस्कोर ने इमारत

1
आपके लिए धन्यवाद, मैंने PHP नियमावली में उस पृष्ठ को याद किया। मैंने अपना उत्तर पूरा करने के लिए लिंक जोड़ा (लेकिन मुझे लगता है कि आपने पहले ही पढ़ लिया था)।
एडम

2

मुझे एक समान समस्या थी, और मैंने जो समाधान किया था वह चर को एक फ़ाइल में लिखना था, फिर उस पर filesize () चलाएं। मोटे तौर पर इस तरह (अनुपयोगी कोड):

function getVariableSize ( $foo ) 
{
    $tmpfile = "temp-" . microtime(true) . ".txt";
    file_put_contents($tmpfile, $foo);
    $size = filesize($tmpfile);
    unlink($tmpfile);
    return $size;
}

यह समाधान बहुत तेज़ नहीं है क्योंकि इसमें डिस्क IO शामिल है, लेकिन यह आपको मेमोरी_गेट_युज ट्रिक की तुलना में कुछ अधिक सटीक देनी चाहिए। यह सिर्फ इस बात पर निर्भर करता है कि आपको कितनी सटीकता की आवश्यकता है।


यह ध्यान दिया जाना चाहिए कि यह समाधान स्ट्रिंग के एकल और एकल आयाम सरणी के लिए काम करता है और इसका उपयोग strlenकरना आसान होगा।
एडम

1

कभी कोशिश नहीं की गई, लेकिन Xdebug के साथ Xdebug के निशान ।collect_assignment s के लिए पर्याप्त हो सकते हैं।


1
function mesure($var){
    $start = memory_get_usage();
    if(is_string($var)){
        $newValue = $var . '';
    }elseif(is_numeric($var)){
        $newValue = $var + 0;
    }elseif(is_object($var)){
        $newValue = clone $var;
    }elseif(is_array($var)){
        $newValue = array_flip($var, []);
    }
    return memory_get_usage() - $start;
}

1

निम्न स्क्रिप्ट एकल चर का कुल मेमोरी उपयोग दिखाता है।

function getVariableUsage($var) {
  $total_memory = memory_get_usage();
  $tmp = unserialize(serialize($var));
  return memory_get_usage() - $total_memory; 
}

$var = "Hey, what's you doing?";
echo getVariableUsage($var);

इसकी जांच करें

http://www.phpzag.com/how-much-memory-do-php-variables-use/

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.