一个简单的问题:是什么导致Arel::Table的@aliases数组在每次使用ActiveRecord进行的搜索时都会变得越来越大?
我使用Rails 5编写了一个简单的web应用程序,当我加载测试它时,内存使用量无限期地增加。在220万次请求之后,进程的驻留内存大小高达1GB。
我通过在执行负载测试之前、之后、10分钟和10,000次请求之后获得堆转储来进行调查。我使用在这里找到的堆转储扩散工具分析堆转储。它说大约有398,000个由Arel::Table#alias()创建的泄漏对象。
这一说法似乎是罪魁祸首:
@aliases << node我确认了Arel::Table的@aliases数组是内存泄漏的来源,在已安装的Arel::Table#alias()版本中添加了对uniq!的调用。
def alias name = "#{self.name}_2"
Nodes::TableAlias.new(self, name).tap do |node|
@aliases << node
end
@aliases.uniq! # locally added this line
end通过对Arel的这一修改,在负载测试期间,我的应用程序的内存使用量保持不变。
据我所知,随着对我的应用程序的每一个请求,@aliases都会增长,并且它会以相同的对象增长。我想知道这是Arel中的一个bug,还是我在我的应用程序中做了一些坏事,导致这个数组在没有被清除或垃圾收集的情况下增长。
该应用程序有四种型号:
模型
class DeviceVendor < ApplicationRecord
end
class Group < ApplicationRecord
end
class RadiusDevice < ApplicationRecord
belongs_to :device_vendor
validates :ipv4_address, :ip => {format: :v4}
end
class RadiusVsa < ApplicationRecord
belongs_to :group
belongs_to :device_vendor
endMigrations
class CreateGroups < ActiveRecord::Migration[5.0]
def change
create_table :groups do |t|
t.string :dn
t.integer :rank
t.timestamps
end
end
end
class CreateDeviceVendors < ActiveRecord::Migration[5.0]
def change
create_table :device_vendors do |t|
t.string :name
t.timestamps
end
end
end
class CreateRadiusDevices < ActiveRecord::Migration[5.0]
def change
create_table :radius_devices do |t|
t.string :ipv4_address
t.string :model_number
t.belongs_to :device_vendor, index: true, foreign_key: true
t.timestamps
end
end
end
class CreateRadiusVsas < ActiveRecord::Migration[5.0]
def change
create_table :radius_vsas do |t|
t.string :radius_attributes
t.belongs_to :device_vendor, index: true, foreign_key: true
t.belongs_to :group, index: true, foreign_key: true
t.timestamps
end
end
end我唯一的HTTP端点基于Group.dn和RadiusDevice.ipv4_address的输入参数搜索Group.dn。下面是涉及到的ActiveRecord调用:
# groups param value is like: ['ou=foo,cn=bar', 'ou=baz,cn=qux']
group = Group.order(rank: :desc).find_by!(dn: params.require('groups'))
# source param value is like: '10.0.0.1'
radius_device = RadiusDevice.find_by!(ipv4_address: params.require('source'))
# RadiusVsa.find_by! is the call that causes Arel::Table#alias() to be invoked
vendor_attributes = RadiusVsa.find_by!(group: group, device_vendor: radius_device.device_vendor)发布于 2016-09-13 18:25:57
事实证明,这个内存泄漏是Arel中的一个bug。在这里一天没有得到响应之后,我们创建了Rails中的问题,现在已经修复了。
https://stackoverflow.com/questions/39460355
复制相似问题