2013-01-24 27 views
7

यह एक PHP 5.3 क्ली एप्लिकेशन से संबंधित है जो बहुत से डेटा को जटिल तरीके से संसाधित करता है, घंटों तक चलने में। किसी ने पाया कि कचरा संग्रह बंद करने से यह तेजी से एक बड़ा सौदा चला सकता है (शायद 50% तक)।PHP का कचरा कलेक्टर क्यों perfomance धीमा, और इसके बिना स्मृति का प्रबंधन कैसे करें?

एकमात्र लेख जो मैंने देखा है, इस प्रदर्शन हिट का उल्लेख है http://derickrethans.nl/collecting-garbage-performance-considerations.html। मुझे यकीन नहीं है कि मैं इसे पूरी तरह से पालन करता हूं, लेकिन ऐसा लगता है कि यह केवल कई परिपत्र संदर्भों के साथ कोड पर लागू होता है।

क्या कोई इस पर कुछ प्रकाश डाल सकता है?

इसके अलावा, हमने जीसी बंद कर दिया है, क्या स्मृति को मैन्युअल रूप से कम करने का कोई तरीका है? अनसेट() का उपयोग करने का सुझाव दिया गया है। एक त्वरित परीक्षण से पता चला है कि ऑब्जेक्ट के आकार के बावजूद अस्सी या तो बाइट अनसेट() द्वारा मुक्त किया जाता है। इससे पता चलता है कि यह संदर्भ को केवल परेशान कर रहा है, जो मैंने ऑनलाइन पढ़ा है। क्या मैं यह सोचने में सही हूं कि ये अस्सी बाइट वैसे भी मुक्त हो जाएंगे, कचरा संग्रह के बिना भी, जब चर का दायरा निकलता है?

उत्तर

4

आपने अभी परिपत्र-संदर्भ-जीसी को अक्षम कर दिया है। नियमित अभी भी काम करता है।

सामान्य जीसी परीक्षण, चाहे zval एस ("मेमोरी") हैं, जिन्हें किसी भी चर या गुणों से संदर्भित नहीं किया गया है, और यह स्मृति मुक्त कर देगा। एक परिपत्र संदर्भ अब दोनों वस्तुओं एक दूसरे के संदर्भ, लेकिन वे दोनों कहीं और से संदर्भित नहीं हैं, इसलिए वे पहुंचा नहीं जा सकता है, दो या अधिक वस्तुओं के संदर्भ एक दूसरे को सीधे या परोक्ष रूप से जब

$a = new stdClass; 
$b = new stdClass; 
$a->b = $b; 
$b->a = $a; 
unset($a, $b); 

। यह है, सर्कुलर-संदर्भ जीसी क्या पता लगाने की कोशिश करता है, लेकिन उन्हें खोजने के लिए, यह हर ज्ञात वस्तु पर पुनरावृत्त होता है और पता चलता है कि यदि "बाहर से" संदर्भ है। यह थोड़ा और जटिल है, लेकिन इसे सरल बनाता है;) इसलिए कई संदर्भों के साथ संरचनाओं में, विशेष रूप से परिपत्र वाले, यह एक बड़ा काम है।

उल्लेख करने के लायक: unset() के साथ आप केवल संदर्भ को हटा दें, लेकिन स्मृति (सीधे) को मुक्त न करें। यह बाद में जीसी द्वारा किया जाता है (और यह एक अच्छा काम करता है :))

+0

मैंने सोचा था कि यह मामला हो सकता है, लेकिन मैनुअल बहुत स्पष्ट नहीं है। तो, क्या नियमित रूप से अक्षम करना असंभव है? (ऐसा नहीं है कि मैं बस दिलचस्पी लेना चाहता हूं) – naomi

+0

@ नाओमी हां, आप इसे अक्षम नहीं कर सकते हैं। इसका कोई कारण नहीं है (प्रभाव बहुत छोटा है) और क्योंकि आप स्मृति को स्वयं PHP के भीतर से मुक्त नहीं कर सकते हैं ('अनसेट()' ऐसा नहीं करता है) आपको एक बड़ी समस्या होगी: डी – KingCrunch

2

unset का उपयोग कर आप अपने कोड से मैन्युअल रूप से चक्र हटा सकते हैं। आप __destruct फ़ंक्शन को कार्यान्वित करके कक्षाओं से चक्र साफ़ करते हैं। unset सभी निजी, संरक्षित या सार्वजनिक चर जो अन्य ऑब्जेक्ट्स का संदर्भ देते हैं।

यदि आप किसी मौजूदा प्रोग्राम में इसे लागू कर रहे हैं तो यह वास्तव में कठिन हो जाता है लेकिन यह करने योग्य है।


class A { 
    public $ref; 
    public function __destruct() { 
     unset($this->ref); 
     echo "destruct"; 
    } 
} 
$a1 = new A(); 
$a2 = new A(); 
$a1->ref = $a2; 
$a2->ref = $a1; 

यह करता नहीं काम:

unset($a1, $a2); 
echo "--"; 
// prints --destructdestruct (in 5.3) 

यह काम करता है:

$a1->__destruct(); 
unset($a1, $a2); 
echo "--"; 
// prints destructdestructdestruct-- (in 5.3) 
+0

आपको मेरा ' '__destruct()' के दूसरे उपयोग के लिए + 1' मुझे उपयोगी लगता है _ever_: डी (पहला वाला "संसाधन बंद करना, डीबी-कॉन्सेक्शन, फाइल, ...") – KingCrunch

+0

ठीक है, इसलिए, अनसेट() स्मृति को मुक्त नहीं करता है, लेकिन यह परिपत्र संदर्भों को हटाता है, इसलिए सर्कुलर संदर्भ कलेक्टर अक्षम होने पर इसका उपयोग करना उचित है (जहां उचित हो)। क्या मुझे यह सही मिला है? – naomi

+0

हां, आप चक्रों को हटाने के लिए 'अनसेट' का उपयोग कर सकते हैं। 'अनसेट' स्वयं स्मृति को मुक्त नहीं करता है, यह संदर्भों को साफ़ करता है। और यदि डेटा के एक हिस्से में कोई संदर्भ नहीं है, तो इसे साफ़ किया जाता है। जीसी संदर्भों को गिनना आसान है , लेकिन चक्रों का पता लगाने में मुश्किल है। – Halcyon