ruby-on-rails - Ruby net/ldap 模块中的内存泄漏

标签 ruby-on-rails ruby ldap

作为我的 Rails 应用程序的一部分,我编写了一个小导入程序,它从我们的 LDAP 系统中吸取数据并将其塞入一个用户表中。不幸的是,与 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

在此先感谢您的帮助/指点!

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

最佳答案

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

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

来自文档:“当 :return_result => false 时,#search 将只返回一个 bool 值,以指示操作是否成功。这可以提高非常大的结果集的性能,因为库可以丢弃每个条目在你的 block 处理它之后从内存中提取。”

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

关于ruby-on-rails - Ruby net/ldap 模块中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3320054/

相关文章:

ruby-on-rails - Rails partials 的依赖关系图

ruby-on-rails - 如何根据规范更改 Rails 应用程序配置?

javascript - 对 Rails 4 如何使用 Paperclip 处理 AJAX 文件上传感到困惑

ruby - 我如何使用 authlogic 对用户进行身份验证?

ruby-on-rails - 将静态 JSON 文件解析为 Rails 对象

php - 如何从 for 更改为 foreach

php - Apache 上的 Docker,如何将变量传递给我的 PHP Web 应用程序?

ruby-on-rails - 面向用户的作业的后台进程?

ruby-on-rails - 如何在 Ruby 中推送数组中的元素?

Python LDAP 将 objectGUID 转换为十六进制字符串并返回