PHP के साथ मेमोरी मुक्त करने में बेहतर क्या है: unset () या $ var = null


244

मुझे लगता है कि दूसरा एक फ़ंक्शन कॉल के ओवरहेड से बचा जाता है ( अपडेट , वास्तव में एक भाषा निर्माण है), लेकिन यह जानना दिलचस्प होगा कि क्या एक दूसरे से बेहतर है। मैं unset()अपने अधिकांश कोडिंग के लिए उपयोग कर रहा हूं, लेकिन मैंने हाल ही में नेट से कुछ सम्मानजनक वर्गों के माध्यम से देखा है जो नेट का उपयोग $var = nullकरते हैं।

क्या कोई पसंदीदा है, और क्या तर्क है?

जवाबों:


234

यह 2009 में परेशान मैनुअल के पेज में उल्लिखित किया गया था :

unset()बस इसका नाम क्या कहता है - एक वेरिएबल को अनसेट करें। यह तत्काल मेमोरी फ़्रीज़िंग को बाध्य नहीं करता है। PHP का कचरा संग्रहकर्ता तब करेगा जब वह फिट होता है - जैसे ही इरादे से, वैसे ही जैसे कि सीपीयू चक्रों की आवश्यकता नहीं होती है, या जैसे ही पटकथा स्मृति से बाहर हो जाएगी, जो भी पहले हो।

यदि आप कर रहे हैं $whatever = null;तो आप परिवर्तनशील डेटा को फिर से लिख रहे हैं। आपको मेमोरी फ़्रीड / सिकुड़ कर तेज़ी से प्राप्त हो सकती है, लेकिन यह सीपीयू साइकल को उस कोड से चुरा सकता है जो वास्तव में जल्द ही उनकी आवश्यकता है, जिसके परिणामस्वरूप एक लंबा समग्र निष्पादन समय होता है।

(2013 से, उस unsetआदमी पृष्ठ में अब उस अनुभाग को शामिल नहीं किया गया है)

ध्यान दें कि php5.3 तक, यदि आपके पास परिपत्र संदर्भ में दो ऑब्जेक्ट हैं , जैसे कि माता-पिता के बच्चे के संबंध में, माता-पिता ऑब्जेक्ट पर अनसेट () कॉल करने से बच्चे के ऑब्जेक्ट में माता-पिता के संदर्भ के लिए उपयोग की जाने वाली मेमोरी मुक्त नहीं होगी। (न ही जब पैरेंट ऑब्जेक्ट कचरा एकत्र किया जाता है तो मेमोरी को मुक्त कर दिया जाएगा।) ( बग 33595 )


प्रश्न " अंतर और अशक्त के बीच अंतर " कुछ अंतरों का विवरण देता है:


unset($a)$aप्रतीक तालिका से भी निकालता है; उदाहरण के लिए:

$a = str_repeat('hello world ', 100);
unset($a);
var_dump($a);

आउटपुट:

Notice: Undefined variable: a in xxx
NULL

लेकिन जब $a = nullउपयोग किया जाता है:

$a = str_repeat('hello world ', 100);
$a = null;
var_dump($a);
Outputs:

NULL

ऐसा लगता है कि यह $a = nullअपने unset()समकक्षों की तुलना में थोड़ा तेज है : प्रतीक तालिका प्रविष्टि को अपडेट करने से इसे हटाने की तुलना में तेज प्रतीत होता है।


  • जब आप एक गैर-मौजूद ( unset) चर का उपयोग करने का प्रयास करते हैं , तो एक त्रुटि उत्पन्न हो जाएगी और चर अभिव्यक्ति के लिए मूल्य शून्य हो जाएगा। (क्योंकि, PHP को और क्या करना चाहिए? प्रत्येक अभिव्यक्ति को कुछ मूल्य में परिणाम की आवश्यकता होती है।)
  • इसके साथ असाइन किया गया अशक्त एक चर अभी भी एक पूरी तरह से सामान्य चर है।

18
ध्यान दें कि यदि $whateverकिसी ऑब्जेक्ट की ओर $whatever = nullइशारा करते हैं , तो पॉइंटर को ओवरराइट करता है, ऑब्जेक्ट को ही नहीं, इसलिए यह मूल रूप से उसी तरह कार्य करता है unset()
ग्रास डबल

1
@VonC: php.net पर अनसेट उद्धरण आप अब और मौजूद नहीं होने का उल्लेख कर रहे हैं।
जुरगेन थेलेन 12

@ JürgenThelen सच है, लेकिन उस पुराने उत्तर की सामग्री अभी भी प्रासंगिक लगती है, नहीं?
वॉनक

1
@VonC: निश्चित रूप से। मुझे यकीन नहीं है कि "सीपीयू साइकिल की जरूरत नहीं है" और "पहले .. स्मृति से बाहर" कचरा संग्रह को ट्रिगर करता है। Stackoverflow.com/q/20230626/693207 देखें । शायद आप कुछ प्रकाश डाल सकते हैं?
जुरगेन थेलेन

1
@ ओमर मैंने उत्तर संपादित किया है: 2009 से अनसेट मैन पेज (मैंने 2009 संस्करण से जोड़ा है) में एक खंड शामिल है जो अब उसी पृष्ठ के वर्तमान संस्करण में मौजूद नहीं है।
VONC

48

unsetवास्तव में एक फ़ंक्शन नहीं है, लेकिन एक भाषा निर्माण है । यह एक returnया एक से अधिक एक फ़ंक्शन कॉल नहीं है include

प्रदर्शन के मुद्दों से अलग, unsetआपके कोड के इरादे को बहुत स्पष्ट करता है।


इसलिए मैंने हमेशा उनका उपयोग किया, व्यक्तिगत रूप से मुझे लगा कि वे $ var = null से बेहतर हैं। वैसे, मैंने हमेशा NULL फुल कैप का उपयोग किया है ... लेकिन अब मुझे नहीं पता कि क्यों?
एलेक्स

1
@VonC: हाँ, मुझे लगा कि, लेकिन आप लोअरकेस का उपयोग सही, गलत और अशक्त क्यों कर सकते हैं?
एलेक्स

3
@alex, आप उस तरह से कर सकते हैं जो परेशान है। उदाहरण के लिए "$ परीक्षण = 4; (परेशान) $ परीक्षण;" - अजीब लेकिन सच है, और यह इसे परेशान करने से पहले $ परीक्षण का मूल्य लौटाता है। बावजूद, PHP मैनुअल पुष्टि करता है कि यह एक भाषा निर्माण है।
थोमसट्रेटर

5
@alex: PSR-2 को सभी कीवर्ड के लिए लोअरकेस की आवश्यकता है
TGR

2
@alex - PHP कीवर्ड केस-असंवेदनशील हैं; आप भी वर्तनी सकता है unsetके रूप में UnSeT, उदाहरण के लिए। समुदाय शैली के मामले में सभी निचले हिस्सों पर बस गया है, लेकिन अन्य आवरण अभी भी काम करते हैं।
मार्क रीड

35

एक चर पर एक अनसेट () करने से, आपने अनिवार्य रूप से 'कचरा संग्रह' के लिए चर को चिह्नित किया है (PHP वास्तव में एक नहीं है, लेकिन उदाहरण के लिए) इसलिए मेमोरी तुरंत उपलब्ध नहीं है। चर अब डेटा नहीं रखता है, लेकिन स्टैक बड़े आकार पर रहता है। शून्य विधि करने से डेटा गिर जाता है और स्टैक मेमोरी को लगभग तुरंत सिकोड़ देता है।

यह व्यक्तिगत अनुभव और दूसरों से भी रहा है। यहां अनसेट () फ़ंक्शन की टिप्पणियों को देखें ।

मैं व्यक्तिगत रूप से एक लूप में पुनरावृत्तियों के बीच अनसेट () का उपयोग करता हूं, ताकि मुझे स्टैक की देरी यो-यो आकार में होने की आवश्यकता न हो। डेटा चला गया है, लेकिन पदचिह्न बना हुआ है। अगले पुनरावृत्ति पर, मेमोरी पहले से ही php द्वारा ली जा रही है और इस प्रकार, अगले चर को प्रारंभ करने के लिए तेज है।


15
NULL को कुछ सेट करने से फायदा हो सकता है यदि NULL को होल्ड करने के लिए आवश्यक मेमोरी उस से कम है जो पहले पकड़े गए वैल्यू को होल्ड करने के लिए आवश्यक है। उदाहरण के लिए, एक लंबी स्ट्रिंग। यदि स्ट्रिंग एक स्थिर नहीं थी और इसकी संदर्भ संख्या शून्य तक गिर जाती है, तो उस मेमोरी को मुक्त किया जाना चाहिए। परेशान क्लीनर है - यह अब एक संदर्भ नहीं रखता है। आपको कचरा संग्रह के लिए इंतजार करना होगा, लेकिन इसे बिना किसी स्मृति के कब्जे के रूप में व्यवहार करना सुरक्षित है, क्योंकि कम स्मृति स्थिति कचरा संग्रह को ट्रिगर करेगी।
थोमसट्रेटर

क्या हम दोनों का उपयोग नहीं कर सकते? अशक्त और फिर परेशान के बराबर?
नबील खान

2
@ नबीलखान मैं सुझाव देता हूं कि आप लूप के अंदर अनसेट () का उपयोग करें और लूप से बाहर निकलने के बाद इसे बंद कर दें। अन्यथा, लूप के अंदर दोनों करने के लिए एक प्रदर्शन प्रभाव पड़ता है। यदि आप लूप्स का उपयोग नहीं कर रहे हैं, तो इसे ठीक कर दें क्योंकि यह पहले से ही पर्दे के पीछे अनसेट () तर्क देता है।
विलियम होरोलिड

27
<?php
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    $a = NULL;
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds\r\n";



$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    unset($a);
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds\r\n";
?>

प्रति ऐसा लगता है कि "= अशक्त" तेज है।

PHP 5.4 के परिणाम:

  • 0.88389301300049 सेकंड का समय लिया
  • 2.1757180690765 सेकंड लिया

PHP 5.3 परिणाम:

  • 1.7235369682312 सेकंड का समय लिया
  • 2.9490959644318 सेकंड का समय लिया

PHP 5.2 परिणाम:

  • 3.0069220066071 सेकंड का समय लिया
  • 4.7002630233765 सेकंड का समय लिया

PHP 5.1 परिणाम:

  • 2.6272349357605 सेकंड लिया
  • 5.0403649806976 सेकंड लिया

PHP 5.0 और 4.4 के साथ चीजें अलग दिखने लगती हैं।

5.0:

  • 10.038941144943 सेकंड का समय लिया
  • 7.0874409675598 सेकंड का समय लिया

4.4:

  • 7.5352551937103 सेकंड का समय लिया
  • 6.6245851516724 सेकंड का समय लिया

ध्यान रखें कि microtime (true) PHP 4.4 में काम नहीं करता है इसलिए मुझे php.net/microtime / उदाहरण # 1 में दिए गए microtime_float उदाहरण का उपयोग करना था।


7
मुझे लगता है कि आपका परीक्षण त्रुटिपूर्ण है। पहला लूप साधारण पुनर्मूल्यांकन है और दूसरा लूप एक ही प्रतीक को नष्ट और पुन: बनाता है। यदि परीक्षण एक सरणी के साथ फिर से किया जाता unsetहै तो तेज होता है। मेरे पास एक परीक्षण है जो बाद में unsetमामले में अस्तित्व की जांच करता है । उस परीक्षण में इसे सेट करना nullथोड़ा तेज है। टेस्ट: pastebin.com/fUe57C51
कन्या

4
@ansur, gc_collect_cyclesअधिक सटीक परिणाम प्राप्त करने के लिए टाइमर शुरू करने से पहले हमेशा कॉल करें ।
पचेरियर

@knyri क्या आप इससे लिंक कर सकते हैं?
नबील खान

@ नबीलखान I के पास अब उस परीक्षा के परिणाम नहीं हैं; लेकिन मेरी पिछली टिप्पणी में परीक्षण कोड की एक कड़ी है।
कन्या

19

यह सरणी तत्वों के साथ एक अंतर बनाता है।

इस उदाहरण पर विचार करें

$a = array('test' => 1);
$a['test'] = NULL;
echo "Key test ", array_key_exists('test', $a)? "exists": "does not exist";

यहाँ, कुंजी 'परीक्षण' अभी भी मौजूद है। हालाँकि, इस उदाहरण में

$a = array('test' => 1);
unset($a['test']);
echo "Key test ", array_key_exists('test', $a)? "exists": "does not exist";

कुंजी अब मौजूद नहीं है।


18

यह संदर्भ द्वारा कॉपी किए गए चर के लिए एक अलग तरीके से काम करता है:

$a = 5;
$b = &$a;
unset($b); // just say $b should not point to any variable
print $a; // 5

$a = 5;
$b = &$a;
$b = null; // rewrites value of $b (and $a)
print $a; // nothing, because $a = null

5
मैं अब कुछ साल php कोडिंग कर रहा हूं और मूल संस्करण को संदर्भित करने के बारे में "&" कभी नहीं देखा। धन्यवाद + 1 :)
क्रिस

1
डॉलर प्रति = 78; $ B $ एक =; सेट नहीं ($ एक); var_dump ($ ख); // 78; var_dump ($ a); // अपरिभाषित चर: a
zloctb

13

वस्तुओं के बारे में, विशेष रूप से आलसी-लोड परिदृश्य में, किसी को यह विचार करना चाहिए कि कचरा कलेक्टर निष्क्रिय सीपीयू चक्रों में चल रहा है, इसलिए मान लें कि जब बहुत सारी वस्तुएं लोड हो रही हैं, तो आप मुसीबत में पड़ सकते हैं।

जीसी को मेमोरी इकट्ठा करने में सक्षम करने के लिए time_nanosleep का उपयोग करें। अशक्त करने के लिए चर सेट करना वांछनीय है।

उत्पादन सर्वर पर परीक्षण किया गया, मूल रूप से नौकरी में 50 एमबी की खपत हुई और फिर रुका हुआ था। 14 एमबी का उपयोग करने के बाद नैनो मेमोरी लगातार मेमोरी थी।

यह कहना चाहिए कि यह जीसी व्यवहार पर निर्भर करता है जो PHP संस्करण से संस्करण में बदल सकता है। लेकिन यह PHP 5.3 पर काम करता है।

जैसे। यह नमूना (कोड लिया गया रूप VirtueMart2 Google फ़ीड)

for($n=0; $n<count($ids); $n++)
{
    //unset($product); //usefull for arrays
    $product = null
    if( $n % 50 == 0 )
    {
        // let GC do the memory job
        //echo "<mem>" . memory_get_usage() . "</mem>";//$ids[$n];
        time_nanosleep(0, 10000000);
    }

    $product = $productModel->getProductSingle((int)$ids[$n],true, true, true);
    ...

3

मुझे अभी भी इस बारे में संदेह है, लेकिन मैंने इसे अपनी स्क्रिप्ट पर आज़माया है और मैं यह जानने के लिए xdebug का उपयोग कर रहा हूं कि यह मेरे ऐप मेमोरी उपयोग को कैसे प्रभावित करेगा। स्क्रिप्ट मेरे कार्य पर इस तरह सेट है:

function gen_table_data($serv, $coorp, $type, $showSql = FALSE, $table = 'ireg_idnts') {
    $sql = "SELECT COUNT(`operator`) `operator` FROM $table WHERE $serv = '$coorp'";
    if($showSql === FALSE) {
        $sql = mysql_query($sql) or die(mysql_error());
        $data = mysql_fetch_array($sql);
        return $data[0];
    } else echo $sql;
}

और मैं returnकोड के ठीक पहले अनसेट करता हूं और यह मुझे देता है: 160200 फिर मैं इसे बदलने की कोशिश करता हूं$sql = NULL और यह मुझे देता है: 160224 :)

लेकिन इस तुलनात्मक पर कुछ अनूठा है जब मैं परेशान नहीं कर रहा हूँ () या NULL, xdebug मुझे 160144 स्मृति उपयोग के लिए दे रहा है

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

सही है अगर मैं गलत हूँ, धन्यवाद


मुझे लगता है कि जब आप $ डेटा [0] आइटम वापस कर रहे हैं, तो संपूर्ण सरणी संदर्भित है / लेकिन यह सिर्फ परिकल्पना है। स्थानीय चर में $ डेटा [0] को कॉपी करने का प्रयास करें, सरणी को शून्य करने और स्थानीय चर वापस करने के लिए सेट करें। अच्छी पृष्ठभूमि यहाँ tuxradar.com/practicalphp/18/1/11 और inc हैphp.net/manual/en/features.gc.php
OSP

2

मैंने के लिए एक नया प्रदर्शन परीक्षण बनाया unsetऔर =null, क्योंकि जैसा कि टिप्पणियों में उल्लेख किया गया है उसमें एक त्रुटि है (तत्वों का पुन: निर्माण)। मैंने सरणियों का उपयोग किया, जैसा कि आप देखते हैं कि यह अब मायने नहीं रखता था।

<?php
$arr1 = array();
$arr2 = array();
for ($i = 0; $i < 10000000; $i++) {
    $arr1[$i] = 'a';
    $arr2[$i] = 'a';
}

$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $arr1[$i] = null;
}
$elapsed = microtime(true) - $start;

echo 'took '. $elapsed .'seconds<br>';

$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    unset($arr2[$i]);
}
$elapsed = microtime(true) - $start;

echo 'took '. $elapsed .'seconds<br>';

लेकिन मैं इसे केवल एक PHP 5.5.9 सर्वर पर परीक्षण कर सकता हूं, यहां परिणाम: - 4.4571571350098 सेकंड - 4.4425978660583 सेकंड लगे

मैं unsetपठनीयता कारणों से पसंद करता हूं ।


2

PHP 7 पहले से ही ऐसे मेमोरी मैनेजमेंट मुद्दों पर काम करता है और इसका कम से कम उपयोग होता है।

<?php
  $start = microtime(true);
  for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    $a = NULL;
  }
  $elapsed = microtime(true) - $start;

  echo "took $elapsed seconds\r\n";

  $start = microtime(true);
  for ($i = 0; $i < 10000000; $i++) {
     $a = 'a';
     unset($a);
  }
  $elapsed = microtime(true) - $start;

  echo "took $elapsed seconds\r\n";

?>

PHP 7.1 आउटपु:

0.16778993606567 सेकंड में 0.16630101203918 सेकंड का समय लिया


1

unsetकोड यदि तत्काल मेमोरी को मुक्त नहीं करता है, तब भी बहुत मददगार होता है और हर बार जब हम किसी विधि से बाहर निकलने से पहले कोड चरणों पर गुजरते हैं तो ऐसा करना एक अच्छा अभ्यास होगा। ध्यान रखें कि तत्काल मेमोरी खाली करने के बारे में नहीं। तत्काल मेमोरी सीपीयू के लिए है, माध्यमिक मेमोरी के बारे में क्या है जो रैम है।

और यह मेमोरी लीक को रोकने के बारे में भी बताता है।

कृपया इस लिंक को देखें http://www.hackingwithphp.com/18/1/11/be-wary-of-garbage-collection--2-2

मैं लंबे समय से परेशान का उपयोग कर रहा हूं।

कोड में इस तरह का बेहतर अभ्यास सभी चर जो पहले से ही सरणी के रूप में इस्तेमाल किया गया है, को अस्थिर करने के लिए।

$data['tesst']='';
$data['test2']='asdadsa';
....
nth.

और just unset($data);सभी चर उपयोग को मुक्त करने के लिए।

कृपया संबंधित विषय को परेशान करने के लिए देखें

PHP में वेरिएबल को अनसेट करना कितना महत्वपूर्ण है?

[बग]


1

रिकॉर्ड के लिए, और इसमें लगने वाले समय को छोड़कर:

<?php
echo "<hr>First:<br>";
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 
echo "<hr>Unset:<br>";
unset($x);
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 
echo "<hr>Null:<br>";
$x=null;
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n";

echo "<hr>function:<br>";
function test() {
    $x = str_repeat('x', 80000);
}
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 

echo "<hr>Reasign:<br>";
$x = str_repeat('x', 80000);
echo memory_get_usage() . "<br>\n";      
echo memory_get_peak_usage() . "<br>\n"; 

यह लौट आता है

First:
438296
438352
Unset:
438296
438352
Null:
438296
438352
function:
438296
438352
Reasign:
438296
520216 <-- double usage.

निष्कर्ष, उम्मीद के अनुसार अशक्त और परेशान मुक्त स्मृति (न केवल निष्पादन के अंत में)। इसके अलावा, एक चर को पुन: सौंपना किसी बिंदु पर दो बार मूल्य रखता है (520216 बनाम 438352)

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