Машина Да Винчи , также называемая многоязычной виртуальной машиной , была проектом Sun Microsystems , целью которого было создание прототипа расширения виртуальной машины Java (JVM) для добавления поддержки динамических языков .
Уже было возможно запускать динамические языки поверх JVM, но цель состоит в том, чтобы упростить реализацию новых динамических языков и повысить их производительность. Этот проект был эталонной реализацией JSR 292 ( Поддержка динамически типизированных языков на платформе Java ). [1]
До Java 7 виртуальная машина Java не имела встроенной поддержки динамически типизированных языков :
JSR 292 ( Поддержка динамически типизированных языков на платформе Java ) [1] предлагает:
invokedynamic
инструкцию на уровне JVM, чтобы разрешить вызов метода на основе динамической проверки типов , [3] [4] [5]После успеха реализации Java в JRuby в конце января 2008 года был запущен проект Da Vinci. [6] Возможности, над которыми экспериментировал Da Vinci, планировалось добавить в Java 7 . Целью проекта является создание прототипа этого JSR, а также других расширений с более низким приоритетом. [7] Первый рабочий прототип, разработанный как патч для OpenJDK , был анонсирован и доступен в конце августа 2008 года. [8] [9] [10]
С тех пор команда JRuby успешно внедрила динамический вызов в свою кодовую базу. Динамический вызов поставляется с выпуском 1.1.5 и будет отключен на JVM без invokedynamic
соответствующих возможностей. [11]
С тех пор проект был интегрирован в кодовую базу JDK 7 [12] , а затем интегрирован в версию Java 7 .
Динамический вызов основан на том факте, что, даже если Java является строго статичным языком на уровне языка, информация о типе гораздо менее распространена на уровне байт-кода .
Однако реализации динамических языков должны иметь возможность использовать JIT-компиляцию (а не отражение ) для достижения хорошей производительности и, таким образом, для компиляции сценариев в байт-код во время выполнения. [ необходима цитация ] Чтобы разрешить запуск виртуальной машины Java , эти байт-коды должны быть проверены перед выполнением, а проверяющий проверяет, что типы являются статическими во всем коде. Это приводит к тому , что этим реализациям приходится создавать множество разных байт-кодов для разных контекстов вызова метода каждый раз, когда меняется сигнатура аргументов .
Это не только использует много памяти, но и заполняет область памяти, называемую Metaspace (Permanent Generation до Java 8), часть кучи, используемую JVM для хранения информации о классах . Память, используемая в этой области, почти никогда не подвергается сборке мусора, поскольку в ней хранятся неизменяемые данные в контексте программ Java; и по этой причине реализации динамических языков могут скомпилировать лишь небольшую часть сценариев. [13]
JSR 292 предлагает:
invokedynamic
байт-код, который позволит JVM оптимизировать вызовы такого типа. [3]Мне удалось успешно подключить InvokeDynamic непосредственно к процессу отправки JRuby! Такое волнение! Код уже находится в багажнике JRuby и будет поставляться с JRuby 1.1.5 (хотя он, очевидно, будет отключен на JVM без InvokeDynamic).
Большая часть indy.patch поступила в виртуальную машину JDK7 в репозитории интеграции моей рабочей группы сегодня около 4:00 утра по тихоокеанскому времени:
Грязный секрет некоторых реализаций JVM, включая Hotspot, заключается в том, что существует отдельная куча (или отдельное поколение кучи), используемая для особых типов данных, таких как определения классов, метаданные классов, а иногда и байт-код или JIT-код. И у него не могло быть более страшного названия: Постоянное Поколение. За исключением редких случаев, объекты, загруженные в PermGen, никогда не удаляются сборщиком мусора (потому что они должны быть постоянными, понимаете?), и если их не использовать очень и очень осторожно, они заполнятся(...)