2016-07-05 6 views
6

मैं एसटीडी का उपयोग करता है एक छोटा सा कार्यक्रम :: कतारstd :: queue तत्वों को पॉप करने के बाद इसकी स्मृति को कम क्यों नहीं करता है?

queue<double> the_queue; 

for(int i = 0; i < 100; i++) 
{ 
    for(int j = 0; j < 5000; j++) 
    { 
     double d = 1.0 * (rand() % 1000); 
     the_queue.push(d); 
    } 
} 

printf("Done pushing\n"); 

while(!the_queue.empty()) 
{ 
    the_queue.pop(); 
} 

printf("Done popping\n"); 

मैं printf("Done pushing\n"); और printf("Done popping\n"); पर 2 breakpoints डाल दिया और कार्यक्रम की स्मृति उपयोग (कार्य प्रबंधक में पता चला है) की जाँच जब breakpoints मारा जाता है लिखा था। Done pushing पर, स्मृति उपयोग ~ 34 एमबी है, लेकिन Done popping पर स्मृति उपयोग अभी भी ~ 34 एमबी है। मुझे आश्चर्य है!

ऐसा क्यों है? क्या इस पर काबू पाने का कोई तरीका है?

+0

यह भी पूरा मामला है कि यदि आप स्मृति को सी ++ (और, विस्तार से, सी) रनटाइम के रूप में मुक्त करते हैं, तो वह रनटाइम शायद इसे ओएस पर वापस नहीं देगा, इसलिए कार्यक्रम अभी तक उस स्मृति का उपभोग करें जहां तक ​​ओएस का संबंध है। – Angew

उत्तर

7

मूल रूप से std::queue एक एडाप्टर कंटेनर है - यह अपने आप से एक कंटेनर है, लेकिन अन्य कंटेनर चारों ओर एक पतली आवरण नहीं है।

उदाहरण के लिए, की सुविधा देता है कतार हस्ताक्षर पर एक नज़र डालें:

template <class T, class Container = deque<T> > class queue; 

के रूप में आप देख सकते हैं, T तत्व कतार में संग्रहीत के प्रकार है, और Container अंतर्निहित कंटेनर है।

और इस अपने प्रश्न का उत्तर है: विभिन्न कंटेनरों स्मृति अलग तरह से संभालती है। अंतर्निहित डेक सिकुड़ सकता है या नहीं भी हो सकता है, लेकिन यह तय करने के लिए अंदर डेक पर निर्भर है।

आप अपने अंतर्निहित कंटेनर के रूप में std::list उपयोग कर सकते हैं। इस मामले में, प्रत्येक पॉप अंतर्निहित सूची नोड मेमोरी हटा देता है।

आप अपने खुद के बारे में या मौजूदा कंटेनर अपनी खुद की स्मृति प्रबंधन पैटर्न मिलान करने के लिए संशोधित कर सकते हैं। आपके कंटेनर को कुछ तरीकों का समर्थन करने की आवश्यकता है (push_back, pop_front के रूप में चूसना) जिसे आप प्रासंगिक ऑनलाइन दस्तावेज़ में पढ़ सकते हैं।

यहाँ एक deque एडाप्टर जो क्षमता में सिकुड़ता है के लिए एक उदाहरण हर 1024 pop कॉल है:

template<class T> 
class DequeAdapater{ 

private: 
    std::deque<T> m_Deque; 
    size_t m_PopCount; 

public: 
    DequeAdapater(): 
     m_PopCount(0){} 

    bool empty() const noexcept{ 
     return m_Deque.empty(); 
    } 

    size_t size() const noexcept{ 
     return m_Deque.size(); 
    } 

    T& front() noexcept{ 
     return m_Deque.front(); 
    } 

    const T& front()const noexcept{ 
     return m_Deque.front(); 
    } 

    T& back() noexcept{ 
     return m_Deque.back(); 
    } 

    const T& back()const noexcept{ 
     return m_Deque.back(); 
    } 

    void push_back(const T& t){ 
     return m_Deque.push_back(t); 
    } 

    void push_back(T&& t){ 
     return m_Deque.push_back(std::move(t)); 
    } 

    void pop_front(){ 
     m_Deque.pop_front(); 
     m_PopCount++; 
     if (m_PopCount%1024U == 0U){ 
      m_Deque.shrink_to_fit(); 
     } 
    } 

} 


template <class T> 
using LeanQueue = std::queue<T,DequeAdapater<T>>; 

तथापि टिप्पणी करते हैं, क्षमता में सिकुड़ते जाने या नई दुबला हिस्सा करने के लिए कतार तत्वों को कॉपी, इसका मतलब है कि स्मृति खपत कम होगी, लेकिन प्रदर्शन खराब हो सकता है। जब कतार दायरे से बाहर चला जाता है

0

क्योंकि pop बस इसके आकार कम हो जाती है, न क्षमता है।

तो अगर आप कतार में अन्य तत्वों में कहें, यह स्मृति को आबंटित करने, नहीं होगा यह सिर्फ पहले से ही आवंटित एक का प्रयोग करेंगे।

+0

मैंने एक वाणिज्यिक कार्यक्रम में एक समान चीज लागू की और इसी तरह की स्थिति हुई है। मेरे मालिक ने मुझसे पूछा कि कार्यक्रम बहुत अधिक स्मृति का उपभोग क्यों करता है। मेँ कुछ कर सकता हूँ? –

+0

शायद एसटीएल कंटेनर बदल रहा है? –

+2

@duong_dajgja शायद 'std :: queue () .swap (the_queue);' –

5

किसी भी स्मृति कतार का प्रबंधन करता है जारी किया जाएगा।

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

इस की बारीकियों malloc में ध्यान रखा जाता है/अपने कार्यक्रम के खिलाफ जुड़ा हुआ है विशिष्ट सी क्रम पुस्तकालय में नि: शुल्क।

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

0

मेमोरी आवंटित और डिलीकेट करना एक कंटेनर के साथ काफी ओवरहेड बन सकता है जिसका नियमित रूप से उपयोग किया जाता है। इस कारण से कंटेनर को जो भी हद तक उपयोग किया जाता है, बढ़ने की अनुमति है। अगर आप स्मृति को पुनः प्राप्त करना चाहते हैं तो आपको इसे स्पष्ट रूप से करना होगा। अक्सर इसमें कंटेनर को गुंजाइश से बाहर जाने की इजाजत दी जाती है क्योंकि मानक (किसी कारण से) स्मृति को मुक्त करने के लिए कोई फ़ंक्शन नहीं देता है। कुछ कंटेनरों (shrink_to_fit()) पर अप्रयुक्त स्मृति को जारी/शायद जारी करने के लिए कोई फ़ंक्शन नहीं है लेकिन इसकी कोई गारंटी नहीं है।

वहाँ शुक्र है, एक मुहावरा है कि स्वैप कहा जाता है स्मृति की मात्रा शुरू कर अपनी करने के लिए एक कंटेनर को कम करने और रीसेट के लिए इस्तेमाल किया जाता है।

आप मूल रूप से एक नया खाली कंटेनर और swap() अपने काम करने वाले कंटेनर के साथ इसकी (खाली) सामग्री बनाते हैं।

// create a temporary empty container and swap its 
// contents with the working container 
std::queue<double>().swap(q); 
संबंधित मुद्दे