«1. Обзор

В этой статье мы рассмотрим Project Valhalla — исторические причины его появления, текущее состояние разработки и то, что он дает ежедневному разработчику Java после его выпуска. .

2. Мотивация и причины проекта Valhalla

В одном из своих выступлений Брайан Гетц, архитектор языка Java в Oracle, сказал, что одним из основных мотивов проекта Valhalla является желание адаптировать язык Java и среду выполнения к современному оборудованию. Когда был задуман язык Java (примерно 25 лет назад на момент написания), стоимость выборки памяти и арифметической операции была примерно одинаковой.

В настоящее время это изменилось, и операции выборки памяти стали от 200 до 1000 раз дороже, чем арифметические операции. С точки зрения дизайна языка это означает, что косвенные обращения, ведущие к выборке указателя, пагубно влияют на общую производительность.

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

Следуя цепочке идентификации, ведущей к указателям и указателям, ведущим к косвенным обращениям, с косвенными обращениями, имеющими недостатки в производительности, логический вывод состоит в том, чтобы удалить те структуры данных, которые не нуждаются в них. Здесь в игру вступают типы значений.

3. Типы значений

Идея типов значений состоит в том, чтобы представлять чистые агрегаты данных. Это связано с отбрасыванием функций обычных объектов. Итак, у нас есть чистые данные, без идентификации. Это, конечно же, означает, что мы также теряем возможности, которые могли бы реализовать с помощью идентификатора объекта. Следовательно, сравнение на равенство может происходить только на основе состояния. Таким образом, мы не можем использовать репрезентативный полиморфизм и не можем использовать неизменяемые или необнуляемые объекты.

Поскольку у нас больше нет идентификатора объекта, мы можем отказаться от указателей и изменить общую структуру памяти для типов значений по сравнению с объектом. Давайте посмотрим на сравнение распределения памяти между классом Point и соответствующим типом значения Point.

Код и соответствующая структура памяти обычного класса Point будут такими:

final class Point {
  final int x;
  final int y;
}

С другой стороны, код и соответствующая структура памяти типа значений Point будут такими:

value class Point {
  int x;
  int y
}

Это позволяет JVM объединять типы значений в массивы и объекты, а также в другие типы значений. На следующей диаграмме мы представляем отрицательный эффект косвенности при использовании класса Point в массиве:

С другой стороны, здесь мы видим соответствующую структуру памяти типа значения Point[]:

Это также позволяет JVM передавать типы значений в стеке вместо того, чтобы выделять их в куче. В конце концов, это означает, что мы получаем агрегаты данных, поведение которых во время выполнения аналогично примитивам Java, таким как int или float.

Но в отличие от примитивов, типы значений могут иметь методы и поля. Мы также можем реализовать интерфейсы и использовать их как универсальные типы. Таким образом, мы можем взглянуть на типы значений с двух разных точек зрения:

    Более быстрые объекты Пользовательские примитивы

В качестве дополнительной вишенки на торте мы можем использовать типы значений как универсальные типы без упаковки. Это напрямую подводит нас к другой большой функции Project Valhalla: специализированным дженерикам.

4. Специализированные обобщения

Когда мы хотим обобщить языковые примитивы, мы в настоящее время используем упакованные типы, такие как Integer для int или Float для float. Эта упаковка создает дополнительный уровень косвенности, тем самым сводя на нет цель использования примитивов для повышения производительности.

«Поэтому мы видим множество специализированных специализаций для примитивных типов в существующих платформах и библиотеках, таких как IntStream\u003cT\u003e или ToIntFunction\u003cT\u003e. Это сделано для сохранения повышения производительности при использовании примитивов.

Итак, специализированные дженерики — это попытка устранить потребность в этих «хаках». Вместо этого язык Java стремится включить универсальные типы практически для всего: ссылок на объекты, примитивов, типов значений и, возможно, даже для void.

5. Заключение

Мы рассмотрели изменения, которые Project Valhalla внесет в язык Java. Двумя основными целями являются повышение производительности и устранение дырявых абстракций.

Улучшения производительности достигаются за счет выравнивания графов объектов и удаления непрямых ссылок. Это приводит к более эффективному размещению памяти и меньшему количеству аллокаций и сборок мусора.

Лучшая абстракция приходит с примитивами и объектами, имеющими более похожее поведение при использовании в качестве универсальных типов.

Ранний прототип Project Valhalla, вводящий типы значений в существующую систему типов, имеет кодовое имя LW1.

Дополнительную информацию о Project Valhalla можно найти на соответствующей странице проекта и JEP:

    Project Valhalla JEP 169: Объекты-значения JEP 218: Обобщения над примитивными типами