Где Ruby отслеживает свои дескрипторы открытых файлов? - программирование
Подтвердить что ты не робот

Где Ruby отслеживает свои дескрипторы открытых файлов?

Что этот вопрос не о

Этот вопрос касается не автоматического закрытия файла с закрытием файла # или синтаксисом открытого файла File #. Это вопрос о том, где Ruby хранит список открытых файловых дескрипторов во время выполнения.

Актуальный вопрос

Если у вас есть программа с открытыми дескрипторами, но у вас нет доступа к связанному объекту File или IO, как вы можете найти ссылку на открытые файловые дескрипторы? Возьмите этот пример:

filename='/tmp/foo'
%x( touch "#{filename}" )
File.open(filename)
filehandle = File.open(filename)

Первый экземпляр файла открывается, но ссылка на объект не сохраняется в переменной. Второй экземпляр хранится в filehandle, где я могу легко получить доступ к нему С#inspect или #close.

Однако отброшенный объект File не исчез; он просто недоступен каким-либо очевидным образом. Пока объект не будет завершен, Ruby должен отслеживать его где-то... но где?

4b9b3361

Ответ 1

TL; DR

Все объекты File и IO хранятся в ObjectSpace.

Ответ

В классе ObjectSpace говорится:

Модуль ObjectSpace содержит ряд подпрограмм, которые взаимодействуют с средством сбора мусора и позволяют вам перемещать все живые объекты с помощью итератора.

Как я протестировал это

Я тестировал это на консоли на Ruby 1.9.3p194.

Тест-тест действительно прост. Идея состоит в том, чтобы иметь два объекта File с разными идентификаторами объектов, но только один из них напрямую доступен через переменную. Другой - "где-то там".

# Don't save a reference to the first object.
filename='/tmp/foo'
File.open(filename)
filehandle = File.open(filename)

Затем я исследовал различные способы взаимодействия с объектами File, даже если я не использовал явную ссылку на объект. Это было удивительно легко, как только я узнал об ObjectSpace.

# List all open File objects.
ObjectSpace.each_object(File) do |f|
  puts "%s: %d" % [f.path, f.fileno] unless f.closed?
end

# List the "dangling" File object which we didn't store in a variable.
ObjectSpace.each_object(File) do |f|
  unless f.closed?  
    printf "%s: %d\n", f.path, f.fileno unless f === filehandle
  end
end

# Close any dangling File objects. Ignore already-closed files, and leave
# the "accessible" object stored in *filehandle* alone.
ObjectSpace.each_object(File) {|f| f.close unless f === filehandle rescue nil}

Заключение

Могут быть другие способы сделать это, но это тот ответ, который я придумал, чтобы поцарапать свой собственный зуд. Если вы знаете лучший способ, отправьте другой ответ. Мир станет для него лучшим местом.