Поведение создания объектов в ColdFusion

В свое время у меня была теория о том, что создание экземпляров объектов по каждому запросу, а не их присутствие в области приложения, было огромным всплеском памяти. Поскольку мои знания ColdFusion возрастали с годами, я не думаю, что я действительно понимал, как CF занимается классами в "черном ящике" фреймворка CF, поэтому я собираюсь попросить об этом для исправления или подтверждения сообщества.

Я просто собираюсь выбросить то, что, как я думаю, происходит:

  • CFC скомпилирован в класс, каждый метод внутри этого CFC компилируется в класс.
  • Эти классы будут находиться в памяти (PermGen) и могут быть записаны на диск на основе настроек администратора CF.
  • Когда создается новый объект или запрашивается шаблон, исходный код хэшируется и сравнивается с хешем, хранящимся в скомпилированном классе.
    • Если есть совпадение, он будет использовать скомпилированный класс в памяти
    • Если скомпилированный класс не существует, он будет компилироваться из источника
    • Если скомпилированный класс существует, но хэш не соответствует, он будет перекомпилирован.
  • В любом случае, когда вы включаете доверенный кеш, ColdFusion больше не будет использовать источник для проверки различий и будет продолжать использовать скомпилированный класс в памяти.
  • Всякий раз, когда вы создаете новый объект, вы получаете новый указатель на скомпилированный класс и классы его методов, и любые события времени выполнения встречаются в псевдоконструкторе. Изменить:. В этот момент я имею в виду использование createObject и наличие какого-либо "свободного" кода вне функций. Когда я говорю указатель, я имею в виду ссылку на память, выделенную для областей объекта (это переменные, функциональные переменные).
  • Если вы запрашиваете init, то запускается конструктор. Потребляемая память в этот момент - это только ваша новая ссылка и любые переменные, заданные в псевдоконструкторе и конструкторе. На самом деле вы не занимаете память для копии всего класса. Изменить:. Для этого шага я имею в виду использование нового оператора или привязку старой школы createObject(). init().

Это устраняет огромную ошибку, которую я, лично, мог слышать на протяжении многих лет, что создание больших объектов в каждом запросе представляет собой массивный всплеск памяти (из-за наличия копии класса, а не только ссылки). Пожалуйста, обратите внимание, что я не сторонник этого, одноэлементный образец поражает. Я просто пытаюсь подтвердить, что происходит под капотом, чтобы предотвратить преследование красных сельдей в устаревшем коде.

Изменить: спасибо за вход для всех, это был действительно полезный Q/A для меня.

Ответы

Ответ 1

Я развиваю CF в течение 14 лет, и я никогда не слышал, чтобы кто-то утверждал, что создание экземпляров CFC для каждого потребляемого памяти из-за компиляции класса. На уровне Java ваш CFML-код напрямую компилируется в байт-код и хранится как классы Java в памяти и на диске. Классы Java не хранятся в куче, а скорее в постоянном поколении, которое не является (обычно) собранным пространством памяти. Вы можете создать так много экземпляров этого CFC, и не будет использоваться больше пространства gen gen, однако пространство кучи будет выделено для хранения данных экземпляра для этого CFC на время его существования. Обратите внимание, что с открытым исходным кодом Railo не использует отдельные классы для методов.

Теперь, если вы создадите очень большое количество экземпляров CFC (или любой переменной), в этом случае, это создаст много крутизны в ваших кучах молодых поколений. Пока жесткие ссылки не будут сохранены после завершения запроса, эти объекты будут удалены из кучи, когда будет запущена следующая небольшая сборка мусора. Это не обязательно плохо, но размеры кучи и GC-паузы всегда должны учитываться при настройке производительности приложения.

Теперь есть причины, чтобы упорствовать в экземплярах CFC, либо в виде одноэлементного шаблона, либо в течение сеанса, запроса и т.д. Одной из причин является накладные расходы на создание фактического объекта. Это часто связано с дисковым вводом/выводом для проверки последних измененных времен. С момента создания объекта значительно возрастала скорость, но по-прежнему довольно далека от родной Java, если вы собираетесь создавать тысячи экземпляров. Другая главная причина заключается в том, что ваши объекты сохраняют состояние в течение срока действия приложения/сеанса/запроса, например, корзины покупок, хранящейся в сеансе, в то время как пользовательские магазины.

И для полноты я попытаюсь категорически адресовать ваши баллы:

  • Для Adobe CF да, для Railo методы являются внутренними классами.
  • Да.
  • Вообще-то, я не верю, что в этом нет никакого хеширования. Все это основано на последнем обновлении datetime в исходном файле.
  • Да, но опять же, без хэширования - он просто пропускает дисковый ввод-вывод для проверки последнего измененного времени жизни
  • Я не думаю, что "указатель" - это правильный термин, так как это означает, что классы Java действительно живут в куче. CF использует собственный загрузчик классов URL для загрузки класса для шаблона, а затем INSTANCE этого класса создается и сохраняется в куче. Я могу понять, как это может сбивать с толку, поскольку у CFML нет понятия "класс". Все просто экземпляр или вообще не существует. Я не уверен, что вы подразумеваете под "событиями времени выполнения" в псевдо-конструкторе ".
  • Чтобы быть ясным, конструктор JAVA уже запускался, когда вы создали CFC. Конструктор CF может быть необязательным, но он имеет нулевое отношение к памяти, потребляемой экземпляром CFC. Опять же, я думаю, что вас тоже излишне повесили на псевдоконструктора. Это просто потерять код внутри компонента, который запускается, когда он создан, и не имеет никакого отношения к памяти, выделенной в куче. Класс Java никогда не копируется, это всего лишь шаблон для экземпляра.