作为我的 Rails 应用程序的一部分,我编写了一个小导入程序,它从我们的 LDAP 系统中吸取数据并将其塞入一个用户表中。不幸的是,与 LDAP 相关的代码在遍历我们的 32K 用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。
这个问题似乎在某种程度上与 LDAP 库有关,因为当我删除对 LDAP 内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是 Net::BER::BerIdentifiedString 和 Net::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/