Утечка памяти Arel::Table @aliases при использовании в Rails 5

Обобщающий вопрос в одном предложении: что может привести к увеличению размера массива Arel::Table @aliases при каждом поиске, выполненном с использованием ActiveRecord?

Я написал простое веб-приложение с использованием Rails 5. Когда я тестировал его под нагрузкой, использование памяти увеличивалось на неопределенный срок. После 2,2 миллиона запросов размер резидентной памяти процесса увеличился примерно до 1 ГБ.

Я провел исследование, получив дампы кучи до, сразу после и через 10 минут после выполнения нагрузочного теста со 100 000 запросов. Я проанализировал дампы кучи, используя инструмент для сравнения дампов кучи инструмент находится здесь. В нем говорится, что было около 398 000 просочившихся объектов, созданных Arel::Table#alias().

Это утверждение кажется виновником:

@aliases << node

Я подтвердил, что массив @aliases Arel::Table является источником утечки памяти, добавив вызов uniq! в моей установленной версии Arel::Table#alias():

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 или я делаю что-то плохое в своем приложении, чтобы заставить этот массив расти без очистки или сбора мусора.

Приложение имеет четыре модели:

Модели

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
end

Миграции

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 ищет RadiusVsa на основе входных параметров для Group.dn и RadiusDevice.ipv4_address. Вот задействованные вызовы 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)

person aogail    schedule 12.09.2016    source источник


Ответы (1)


Оказывается, эта утечка памяти — ошибка в Arel. После отсутствия ответов в течение дня мы создали проблему в Rails, которая теперь исправлена. .

person aogail    schedule 13.09.2016