Ruby net/ldap模块中的内存泄漏

Sea*_*ins 5 ruby ldap ruby-on-rails

作为我的Rails应用程序的一部分,我编写了一个小的导入程序,它从我们的LDAP系统中吸取数据并将其变成User表.不幸的是,与LDAP相关的代码在迭代我们的32K用户时泄漏了大量内存,而我无法弄清楚如何解决这个问题.

这个问题似乎以某种方式与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况很好地稳定了.此外,正在激增的对象是Net :: BER :: BerIdentifiedStringNet :: BER :: BerIdentifiedArray,它们都是LDAP库的一部分.

当我运行导入时,内存使用量最终达到1GB以上.如果存在问题,我需要找到一些方法来纠正我的代码,或者解决问题所在,解决LDAP内存问题.(或者如果有一个更好的LDAP库用于Ruby的大型导入,我也会对此持开放态度.)

这是我的代码的相关部分:

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
Run Code Online (Sandbox Code Playgroud)

提前感谢任何帮助/指针!

顺便说一下,我也在net/ldap支持论坛上询问了这个问题,但没有得到任何有用的指示.

Dan*_*son 8

需要注意的一件非常重要的事情是,您永远不会使用方法调用的结果.这意味着你应该传递:return_result => falseldap.search:

ldap.search(:base => base_dn, :filter => filter, :return_result => false ) do |entry|
Run Code Online (Sandbox Code Playgroud)

从文档:"当:return_result => false时,#search将仅返回一个布尔值,以指示操作是否成功.这可以提高非常大的结果集的性能,因为库可以在块处理后丢弃内存中的每个条目它."

换句话说,如果你不使用这个标志,所有条目都将存储在内存中,即使你不需要它们!所以,使用此选项.