Valhalla项目:了解Java史诗级重构

译文
开发 前端
在Java中,除了int这样的原语之外,所有的事物都是对象。事实证明,这一设置对Java产生了巨大的影响,这些年来,这种影响越来越大。这个看似微不足道的设计决策会在集合和泛型等关键领域引起问题。它还限制了某些性能优化。

​译者 | 李睿

审校 | 孙淑娟​

在Java中,除了int这样的原语之外,所有的事物都是对象。事实证明,这一设置对Java产生了巨大的影响,这些年来,这种影响越来越大。这个看似微不足道的设计决策会在集合和泛型等关键领域引起问题。它还限制了某些性能优化。Java语言重构项目Valhalla旨在纠正这些问题。Valhalla项目负责人Brian Goetz表示,Valhalla将“弥合原语类和对象之间的裂痕”。

可以说,Valhalla项目是一次史诗级的重构,旨在解决自Java诞生以来一直隐藏在平台中的技术债务。这种彻底的进化证明了Java不仅是经典,而且仍然处于编程语言设计的前沿。以下了解Valhalla项目的关键技术组件,以及为什么它们对Java的未来如此重要。

Java中的性能问题 ​

当Java在上世纪90年代首次引入时,决定所有用户创建的类型都是类。只有少数原语类被当作特殊类型。它们不是作为基于指针的类结构处理的,而是直接映射到操作系统类型。8种原语类型是int、byte、short、long、float、double、boolean和char。

直接将这些变量映射到操作系统对性能来说更好,因为数值操作在去掉对象的引用开销时性能更好。而且,所有数据最终在程序中都解析为这8种基本类型。类只是一种结构和组织层,它提供了更强大的处理基本类型的方法。另一种结构是数组。原语、类和数组构成了Java表达能力的全部范围。

但是原语是与类和数组不同的,程序员已经学会了直观地处理这些差异。例如,原语是按值传递,而对象是按引用传递。其中的原因相当深刻,这归结为身份的问题。可以说,原语值是可替换的:intx=4是整数4,无论它出现在哪里。可以在equals()vs==中看到这种区别,前者测试对象的值等价性,后者测试对象的同一性。如果两个引用在内存中共享相同的空间,它们满足==,这意味着它们是同一个对象。任何设置为4的int类型也满足==,而int类型根本不支持.equals()。

Java虚拟机(JVM)可以利用处理原语的方式来优化存储、检索和操作原语的方式。特别是,如果平台确定一个变量没有改变(也就是说,它是常数或不可变的),那么就可以对其进行优化。

相比之下,对象则不适合这种优化,因为它们有一个身份。作为类的实例,对象所保存的数据既可以是原语,也可以是其他类。对象本身用一个指针句柄来寻址。这就创建了一个引用网络:对象图。每当某个值被更改时(或者即使它可能被更改),JVM都必须维护对象的最终记录以供参考。需要引用对象是一些性能优化的障碍。

性能上的困难还不止于此。对象作为引用桶的特性意味着它们以一种非常松散的方式存在于内存中。Fluffy是一个技术术语,用来描述JVM无法压缩对象以最小化其内存占用这一事实。当一个对象有对另一个对象的引用作为其组成的一部分时,JVM被迫维护该指针关系。(在某些情况下,巧妙的优化可以帮助确定嵌套引用是特定实体的唯一句柄。)

在他撰写的一篇博客文章中,Goetz使用了一系列点来说明引用的非密集性可以使用类。假设有一个Landmark类,它有一个名称和一个地理位置字段。这意味着一个像图1所示的内存结构:

图1 Java对象的“蓬松”内存占用

想要实现的是在适当的时候保存对象的能力,如图2所示

图2. 内存中密集的对象

这就是早期设计决策对Java平台的性能挑战的概述。以下考虑这些决策如何在三个关键领域影响性能。

问题1:方法调用和传递值 ​

内存中对象的默认结构对于内存和缓存来说都是低效的。此外,还有机会在方法调用约定方面取得进展。能够将按值调用参数传递给具有类语法的方法(在适当的情况下)将带来更高性能和好处。

问题2:箱子和自动装箱​

除了低效率之外,原语和类之间的区别还带来了语言级的困难。创建像Integer和Long这样的原语“箱”(以及自动装箱)是为了减轻这种区别所带来的问题。但是,它并不能真正解决这些问题,而且它给开发人员和机器都带来了一定程度的开销。作为开发人员,必须了解并记住int和Integer(以及ArrayList<Integer>, int[], Integer[],以及缺少ArrayList<int>)之间的区别。与此同时,机器必须在两者之间进行转换。

在某种程度上,装箱模糊了这些实体如何工作的底层细微差别,因此很难同时了解类语法的强大功能和原语的性能。

问题3:泛型和流​

在泛型中,所有这些考虑因素都非常重要。泛型旨在使跨功能的泛化更容易、更显式,但这组非对象变量(原语)的挑剔存在只会导致它崩溃。<int>不存在,因为int根本不是一个类,它不是对象的后代。

这个问题在集合和流等库中也有体现,通过提供IntStream和其他非泛型变体,泛型库函数的理想被迫处理int与Integer、long与long等现实。

Valhalla的解决方案:值类和原语类​

Valhalla计划从根本上解决这些问题。第一个也是最基本的概念是值类。这里的思想是,可以定义一个类,它具有类的所有优点,比如具有方法并能够实现泛型,但没有标识。在实践中,这意味着类是不可变的,不能是布局多态的(其中超类可以通过抽象属性对子类进行操作)。

值类为人们提供了一种清晰而明确的方式来获得所追求的性能特征,同时仍然可以访问类语法和获得行为的好处。这意味着库构建者也可以使用它们,从而改进API设计。

更进一步的是原语类,它类似于一个更极端的值类。本质上,原语类是一个真正的原语变量的薄包装器,但带有类方法。这有点像自定义的流线型原语箱。改进在于使装箱系统更加显式和可扩展。此外,由原语类包装的原语值保留了原语的性能特征(没有底层的装箱和拆箱)。因此,原语类可以在任何类可以存在的地方使用——例如,在Object[]数组中。基本类型不能为空(它们不能被设置为空)。

一般来说,Valhalla项目使原语和用户定义类型更加接近。这为开发人员在纯原语和对象之间提供了更多的选择,并使权衡变得明确。它还使这些操作总体上更加一致。特别是,新的原语系统将使原语和对象的工作方式、它们的装箱方式以及如何添加新的原语和对象变得更加流畅。

Java的语法将如何变化​

Valhalla已经看到了一些不同的语法建议,但现在项目有了明确的形式和方向。两个新的关键字修改了类关键字:value和primitive。用value class语法声明的类将放弃其标识,并在这一过程中获得性能改进。除了可变性和多态限制外,对类的大部分期望仍然适用,并且此类类可以完全参与泛型代码(例如object[]或ArrayList<T>)。值类默认为null。

原语类语法创建的类比传统对象和传统原语更进一步。这些类默认为字段的基础值(int为0,double为0.0,等等),并且不能为空。原语类在优化方面获得最多,在特性方面牺牲最多。原语类最终将被用于对平台中的所有原语建模,这意味着用户和库定义的原语添加将与内置组件参与到同一个系统中。

IdentityObject和ValueObject​

IdentityObject和ValueObject是Valhalla项目中引入的两个新接口。这将允许运行时确定正在处理的类的类型。

对于有经验的Java开发人员来说,最根本的语法更改可能是增加了.ref成员。所有类型现在都有V.ref()字段。这个字段的操作类似于基本类型上的box,所以是int.ref类似于用Integer包装int。普通类将解析.ref到它们的引用。总体效果是提供了一种一致的方式来请求变量的引用,而不管变量的类型是什么。这也会导致所有Java数组都是“协变的”,也就是说,它们都起源于Object[]。因此,int[]现在来自Object[],可以在任何需要的地方使用。

结论​

值类和原语类将对Java及其生态系统产生重大影响。当前的路线图计划首先引入值类,然后是原语类。接下来将迁移现有的原语装箱类(如Integer)以使用新的原语类。有了这些特性,下一个被称为通用泛型的特性将允许原语类直接与泛型一起使用,从而消除API中重用的许多复杂性。最后,专门的泛型(允许T扩展Foo的所有表达能力)将与原语类集成。

Valhalla项目及其组成项目仍处于设计阶段,但越来越接近项目周围的活动表明,价值类很快就会出现在JDK预览中。

在这些有趣的技术工作之外,让人感觉到了Java的持续活力。人们有意愿也有能力去识别平台在哪些方面可以从根本上进行改进,这是保持Java相关性的真正承诺的证据。而Project Loom是对Java未来持乐观态度的另一个项目。

原文标题:Project Valhalla: A look inside Java’s epic refactor作者:Matthew Tyson

责任编辑:华轩 来源: 51CTO
相关推荐

2023-11-13 08:21:35

阿里云盘

2021-01-05 14:22:35

比特币货币投资

2023-09-25 08:08:56

CAA开发者团队

2017-09-14 16:50:37

Dell笔记本

2022-04-25 20:52:22

UbuntuLinux

2021-12-13 17:44:51

程序员漏洞开发

2022-05-26 05:10:46

邮件诈骗钓鱼邮件加密

2021-01-14 11:05:41

项目配置属性

2021-08-17 16:18:33

数字人民币数字货币区块链

2022-05-30 14:04:23

Log4j远程代码漏洞

2023-12-28 14:38:27

2023-07-14 12:10:08

AI自主权离职

2020-11-11 16:46:35

苹果macOS操作系统

2023-05-26 09:49:21

英伟达AI

2023-05-19 10:38:52

ChatGPTOpenAIiOS

2021-12-11 13:22:10

漏洞公司Log4j

2017-07-07 16:07:41

2023-05-25 13:39:00

AI功能分隔带
点赞
收藏

51CTO技术栈公众号