2010-07-23 17 views
5

मेरे रेल एप्लिकेशन के हिस्से के रूप में, मैंने एक छोटा आयातक लिखा है जो हमारे एलडीएपी सिस्टम से डेटा में बेकार है और इसे उपयोगकर्ता तालिका में क्रैम करता है। दुर्भाग्यवश, हमारे 32 के उपयोगकर्ताओं को सक्रिय करते समय एलडीएपी से संबंधित कोड मेमोरी की भारी मात्रा में लीक करता है, और मैं इस मुद्दे को ठीक करने का तरीका समझने में सक्षम नहीं हूं।रूबी नेट/एलडीएपी मॉड्यूल में मेमोरी लीक

समस्या एलडीएपी लाइब्रेरी से किसी तरह से संबंधित प्रतीत होती है, जब मैं एलडीएपी सामानों को कॉल हटा देता हूं, तो स्मृति उपयोग अच्छी तरह से स्थिर हो जाता है। इसके अलावा, प्रजनन करने वाली वस्तुएं नेट :: बीईआर :: BerIdentifiedString और नेट :: बीईआर :: BerIdentifiedArray, एलडीएपी लाइब्रेरी के दोनों भाग हैं।

जब मैं आयात चलाता हूं, तो स्मृति उपयोग अंततः 1 जीबी से अधिक हो जाता है। अगर समस्या है तो मुझे अपने कोड को सही करने के लिए कुछ रास्ता ढूंढना होगा, या एलडीएपी मेमोरी के मुद्दों के आसपास काम करना होगा यदि समस्या है। (या रूबी के लिए बड़े आयात के लिए एक बेहतर LDAP पुस्तकालय हो, तो, मुझे लगता है कि के लिए खुला के रूप में अच्छी तरह से कर रहा हूँ।)

यहाँ हमारे मेरी कोड के उचित सा है:

require 'net/ldap' 
require 'pp' 

class User < ActiveRecord::Base 
    validates_presence_of :name, :login, :email 

    # This method is resonsible for populating the User table with the 
    # login, name, and email of anybody who might be using the system. 
    def self.import_all 
    # initialization stuff. set bind_dn, bind_pass, ldap_host, base_dn and filter 

    ldap = Net::LDAP.new 
    ldap.host = ldap_host 
    ldap.auth bind_dn, bind_pass 
    ldap.bind 

    begin 
     # Build the list 
     records = records_updated = new_records = 0 
     ldap.search(:base => base_dn, :filter => filter) do |entry| 
     name = entry.givenName.to_s.strip + " " + entry.sn.to_s.strip 
     login = entry.name.to_s.strip 
     email = login + "@txstate.edu" 
     user = User.find_or_initialize_by_login :name => name, :login => login, :email => email 
     if user.name != name 
      user.name = name 
      user.save 
      logger.info("Updated: " + email) 
      records_updated = records_updated + 1 
     elsif user.new_record? 
      user.save 
      new_records = new_records + 1 
     else 
      # update timestamp so that we can delete old records later 
      user.touch 
     end 
     records = records + 1 
     end 

     # delete records that haven't been updated for 7 days 
     records_deleted = User.destroy_all(["updated_at < ?", Date.today - 7 ]).size 

     logger.info("LDAP Import Complete: " + Time.now.to_s) 
     logger.info("Total Records Processed: " + records.to_s) 
     logger.info("New Records: " + new_records.to_s) 
     logger.info("Updated Records: " + records_updated.to_s) 
     logger.info("Deleted Records: " + records_deleted.to_s) 

    end 

    end 
end 

किसी भी मदद के लिए अग्रिम धन्यवाद/संकेत!

वैसे, मैंने नेट/एलडीएपी समर्थन मंच में इसके बारे में भी पूछा था, लेकिन वहां कोई उपयोगी पॉइंटर्स नहीं मिला।

+0

आप कनेक्शन स्ट्रिंग को असंबद्ध कहां कर रहे हैं? ldap.unbind? – Mike

+0

हाय माइक, दस्तावेज़ों में एक अनइंड विधि शामिल नहीं है, न ही नमूना कोड में से कोई भी है, इसलिए मुझे लगा कि इसकी आवश्यकता नहीं थी। (http://net-ldap.rubyforge.org/) इसके अलावा, किसी भी रिकॉर्ड के माध्यम से फिर भी शुरू करने के बाद तक कोई अंत नहीं होगा, है ना? पुनरावृत्ति के दौरान स्मृति रिसाव हो रहा है। मैं दिमागी तूफान की सराहना करता हूं। –

+0

इस खोज से डेटा सेट कितना बड़ा है? मुझे लगता है कि डेटा एक या दो बार डुप्लिकेट हो रहा है। रूबी का संस्करण भी सहायक हो सकता है। इसके अलावा, क्या आप 'फ़िल्टर' का उपयोग कर रहे हैं जिसका आप उपयोग कर रहे हैं? आखिरकार, मामले की संभावना नहीं है, लेकिन मैंने अन्य प्लेटफार्मों पर एलडीएपी पुस्तकालयों को देखा है, नेस्टेड समूहों पर बहुत अधिक पुनरावृत्ति करते हैं - संचार के टीसीपी डंप को देखते समय मुझे केवल एहसास हुआ ... – Brian

उत्तर

8

ध्यान देने योग्य एक बहुत ही महत्वपूर्ण बात यह है कि आप कभी भी विधि कॉल के परिणाम का उपयोग नहीं करते हैं। इसका मतलब है कि आप :return_result => falseldap.search को पारित करना चाहिए: डॉक्स से

ldap.search(:base => base_dn, :filter => filter, :return_result => false) do |entry| 

: "जब: return_result => झूठी, #search केवल एक बूलियन वापस आ जाएगी, इंगित करने के लिए आपरेशन सफल रहा है कि क्या इस के साथ प्रदर्शन में सुधार कर सकते हैं। बहुत बड़ा परिणाम सेट, क्योंकि आपकी ब्लॉक प्रक्रियाओं के बाद लाइब्रेरी मेमोरी से प्रत्येक प्रविष्टि को त्याग सकती है। "

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

+0

ब्लॉक पूर्णांक का एक सेट देता है। यह एक अच्छा सूचक है लेकिन मुझे संदेह है कि यह वर्णित बड़ा सौदा है। –

+0

मैंने "ब्लॉक के परिणाम" के बजाय "विधि कॉल के परिणाम" के लिए पहली वाक्य को दोहराया, जैसा कि महत्वपूर्ण है। लेकिन मैं ईमानदारी से सोचता हूं कि इससे एक बड़ी सुधार होगी। –

+0

डैनियल, आप सही हैं। मैंने अभी परीक्षण किया है कि एक क्वेरी के साथ जो ~ 50000 परिणाम देता है। इसके साथ: return_result => झूठा क्लाइंट परिणाम के दौरान लगभग 50 एमबी रैम रहता है जिसके परिणामस्वरूप यह इस पैरामीटर के बिना ~ 600 एमबी तक जाता है। –

संबंधित मुद्दे