松岗做网站费用,公司营销网站制作,网站建设策划书附录,服装网站建设视频扁平化堆容器是OpenJDK Valhalla 项目提出的#xff0c;其主要目标为将值对象扁平化到其堆容器中#xff0c;同时支持这些容器的所有指定行为#xff0c;从而达到不影响原有功能的情况下#xff0c;显著减少内存空间的占用#xff08;理想条件下可以减少24倍#xff09;。…扁平化堆容器是OpenJDK Valhalla 项目提出的其主要目标为将值对象扁平化到其堆容器中同时支持这些容器的所有指定行为从而达到不影响原有功能的情况下显著减少内存空间的占用理想条件下可以减少24倍。
1.前言
1.1.容器
Java 变量可以是堆对象内的字段也可以是堆数组内的数组元素这些是可能的堆变量。还有非堆变量它们是线程堆栈上活动框架内的局部变量或堆栈元素。 容器只是 Java 语言或 Java VM 定义的变量的实现。 容器这个术语关注的是变量的底层、具体的实现特征而不是其逻辑的、指定的行为。
所有 Java 和 VM 变量除原始类型的变量外如int都指定为引用并且必须按引用的方式运行。除非有任何特殊约定否则它们将初始化为null并以指针的形式读取和写入。如果将它们类型化为基于值的类或 Valhalla 值则即使在竞争条件下它们的连续值也会表现出完全一致的行为。
尽管其逻辑行为使变量看起来好像只包含对一系列连续分配的对象和/或 null的单个引用但 Valhalla 允许将变量底层的容器展平。尽管它的行为类似于指针但它的格式类似于 int 变量。如果值有多个字段它的行为就像几个变量int、引用等这些变量彼此靠近存储并且都在展平的容器内。容器可能还具有表示空引用的逻辑存在的策略即使容器在物理上根本没有引用。在 Valhalla 之前每个变量的逻辑特征及其类型或多或少直接决定了容器的物理结构。也有例外例如标量化优化它会将堆对象重新组织到线程寄存器中。这就是为什么 “容器”一词主要在 Valhalla 的设置中有用。
我们不会过多谈论非堆容器的实现因为它们由 JIT 代码或解释器管理。幸运的是它们永远不会受到竞争条件的影响因为这样的容器仅由创建它的线程使用。您可以将值的非堆容器视为多个机器寄存器和/或线程堆栈位置通常彼此不相邻。
位于堆中意味着容器位于 Java 堆上的封闭存储块、对象或数组中。通常存储块的标识是动态计算的。静态字段是例外它们的包含块是常量。但块内的容器必须具有相对于块的可预测位置。它还必须具有可预测的静态定义格式以便从在多个线程中运行的多个代码位置高效地访问值。与格式对于任何给定的容器相关联的是访问方法用于将值对象或 null写入或读出或可能是 CAS堆容器的过程。
具体来说就是堆位置是动态计算的。除静态字段外任何给定的访问都可能是对许多动态选择的封闭对象或数组之一的访问。相比之下堆栈或局部变量是线程私有的只能通过一个方法调用访问并且位于堆栈框架内激活后不再进行进一步的动态选择。
并且堆位置是静态格式化的。为了使访问方法平等地应用于许多动态选择的位置所有这些位置必须具有通用布局以便访问方法能够工作。这要求 VM 发明此类布局与访问方法相结合并将它们适当地分配给不同类型的容器。请注意final、volatile 或 normal 值字段可能具有不同的布局和访问方法。此外可空和非可空值容器可能具有不同的布局和访问方法。根据约定每个不同的堆栈或局部变量都可以由特定于该变量的 JIT 代码直接在寄存器或控制堆栈位置中操作。局部变量需要布局或访问方法之类的东西的唯一时间是当它必须跨越方法调用边界作为参数或返回值并且方法调用未内联时。然后应用 VM 的调用序列规则。
那什么是访问方法访问方法可以被认为是 VarHandle 方法的底层体现。它可以读取、写入甚至 CAS 容器中的值。访问方法需要作为参数包含容器的存储块的基地址。如果容器是数组则访问方法还需要索引来识别所有数组元素中的哪个容器。
最后让我们回顾在 Valhalla 之前堆容器只有少数几种固定格式。如果容器的类型不是原语字节、双精度等它只是指向另一个堆对象的指针当然也可以是空值。因此每个 Valhalla 之前的堆容器都可以非常舒适地装入机器字中。这种轻松和舒适是以指针在多个堆块中移动为代价的。即使一个对象只有一个字节字段将其放入另一个对象的容器中也是一件大事可能需要 64 位用于容器在堆中保存指向它的指针还需要另外 128 位用于分配堆块以包含该字节字段。Valhalla 可以简单地将单个“有效负载”字节放入容器中而无需指针或块从而将占用空间减少高达 24 倍在这种极端情况下。
1.2.一致性
Java 语言和 VM 都保证从变量读取始终保持一致这是 Java 内存模型定义的特定意义除非存在降低一致性的特殊规定在 Valhalla 之前这是不可能的。如果引用存储在变量中则只能观察到与先前引用相关联的类字段组合。没有办法“凭空”创建一个引用或者以某种方式混合其他两个引用的特征。即使多个线程争相读取变量中的值变量也必须将每个连续的变量值与所有其他值分开。
在 Valhalla 中当容器在物理上被扁平化时事情会变得更加困难。Valhalla 值在逻辑上仍然是存储在变量中的引用。虚拟机字节码指令将每个连续的值作为单个自洽对象引用存储到变量中。但是如果多字段值类在容器中被扁平化则值的物理字段可能会通过单独的硬件指令分别写入容器的存储中。如果线程同时读取和写入容器则某个线程可能会观察到一个值包含从不同逻辑值获得的不同物理字段值的混合这些值是在不同的时刻写入的。这种现象称为逐字段撕裂。这是 Java 内存模型保证的一致性的一种特殊故障。
因此一个非常合理的物理活动可能会产生一个不合理的逻辑结果即一个“撕裂”的值类实例凭空而来没有人真正构建过而且大概没有人愿意看到。我们确实希望声称扁平化容器是对基于值的类的优化现在成为值类。但如果它通过逐个字段撕裂凭空创建新值那么这种优化就会被破坏。
值得注意的是这里没有任何内容表明单个字段可能因竞争而损坏无论是在 Valhalla 之前还是之后。值或任何其他对象内的单个字段值永远不会因竞争而撕裂。作为一个狭隘的例外可变的 long 或 double 字段可能会显示字撕裂但这对于值来说是不可能的因为 long 或 double 将存储在值类的安全发布的最终字段中。同样如果对象未安全发布字段的预初始化值空或零也可能会在竞争下泄漏这是一种看起来像字段撕裂的不一致。但对于值来说这同样是不可能的因为发布规则对它们更加严格。这些限制与当前对灵活构造函数主体的工作相结合值必须始终在调用 super 之前初始化其字段而不是之后。
完全一致性是指多字段值对象的所有字段必须作为一个单元进行读取和写入即整个值对象。也就是说值对象的竞争不会比类似的基于值的类对象多。完全一致性的反义词是字段松散一致性或简称为松散一致性这是 Valhalla 中新增的一个容器属性它允许竞争条件混合和匹配来自不同逻辑写入的不同物理字段值。
在 Valhalla 之前读取或写入类值对象[基于值的类]的唯一方法是加载或存储单字机器地址即指向类值对象的不变实例的指针。它也可以为空。Java 内存模型 (JMM) 规定不可能通过这种加载的指针读取不一致的字段值。因此所有 Valhalla 之前的类值对象都作为一致单元进行读取和写入通过物理指针。在 Valhalla 之前始终存在完全一致性。
关于一致性可以详细阐述的还是有很多正如上述所示这就是为什么 Valhalla 之前的规范没有过多谈论一致性我们在这里使用该术语的方式。一个例外是长整型和双整型基元的字拆分这是 Valhalla 中字段拆分的前身。字拆分的工作方式就像将长整型作为一个值类分成两个 32 位字段然后对其进行逐字段拆分一样。
那么如果不让值看起来不一致Valhalla 之前的竞争还能做什么呢有两点不同的线程可以在不同的时间读取不同的指针值并且值的出现顺序可能并不总是完全合理。此外如果引用指向可变对象而不是基于值的类则对该对象字段的读取可能会变得彼此不一致这仅仅是因为竞争线程可能会读取一个字段的“旧”值和另一个字段的“新”值尽管某种方法正在努力同时一致地更新字段。
具体来说想象一个堆中的复数值对象由具有两个字段 {re0,im1} 的“旧”写入写入。现在想象一个存储 {re2,im3} 的“新”写入以及读取变量的不同线程。该线程可以观察到什么至少我们不会期望“凭空而来”的结果永远不会有 re99而只有 re0 或 re2对于 im1、im3 也是如此。但在某些硬件上如果不特别注意一致性线程可能会读取旧字段值和新字段值的“撕裂”混合{re0,im3} 或 {re2,im1}。请注意撕裂的值 {re0,im3} 从未写入过因此如果应用程序可以读取它那就有些可疑了而且撕裂的值可能会间歇性出现这甚至更可疑。虽然对于复数来说这可能是可以接受的行为但这种逐字段撕裂可能会破坏具有微妙内部不变量的值对象的完整性。 例如间隔对象可能要求其结束字段大于其起始字段但撕裂会破坏这个不变量。这就是为什么 Valhalla 中的值默认是完全一致的。
在硬件层面现代 CPU 承诺在一条指令中加载或存储甚至 CAS 操作值时将原子性保持在 64 位对齐以内有时保持在 128 位再次对齐以内。这与我们的一致性概念有关如果您将机器字视为由字节构成的值好像每个字节都是一个值字段则原子加载或存储将保持完全一致性即使在最具挑战性的竞争条件下也不会出现“字节撕裂”。当读取和写入是原子时它们不会在读取或写入字时拆分字并且字的所有位和字节都会同时更改无论哪个线程正在观察该字。但是如果两个 32 位写入指令将两个字段存储到一个 64 位变量中则无法保证原子性并且可能会发生某种字节撕裂。
现代 CPU 并不保证任何多条写入指令序列的原子性。通常没有适用于多条写入指令的“锁定前缀”以使它们的内存效果成为全有或全无的事务。英特尔的 TSX 功能据称可以做到这一点显然没有成功。我们只能使用 64 位原子性或者最多并且有性能风险128 位原子性。
在 Valhalla 原型中实验性值类注释 LooselyConsistentValue 拒绝完全一致性允许 VM 使用更快的访问方法但可能会导致字段撕裂。
1.3.什么是扁平化
扁平化是对容器的任何重组它用一组直接包含值数据的子字段替换单个指针指向其他地方的某些值数据。
也就是说每个子字段都实现了值的字段。之所以称为子字段是因为值本身位于某个较大对象的字段中。子字段是字段的字段。如果声明值包含值则可以嵌套此关系。但在某种意义上子字段相当于顶级包含对象的字段并且它属于存储在对象中的扁平值这一事实是一种观点。
举例说明示列代码如下
value record Complex(double re, double im) { }
class TwoValues {Complex a, b;// layout: // a: {double, double}// b: {double, double}// null channels (explained elsewhere):// a.NC: byte, b.NC: byte;
}此示例对象的布局与具有四个双精度字段和两个字节字段的 Valhalla 前期对象的布局大致相同。但由于它嵌套了值因此它包含两个容器每个容器都被展平为两个子字段和一个合成空通道。
由于多种原因扁平化堆容器对 VM 实现者来说是一个挑战。光是记录在哪里使用哪种格式就已经够难的了。让加载和存储的速度至少与“经典”基于指针的加载和存储一样快是件棘手的事。尽量减少碎片损失以免削弱 Valhalla 减少占用空间的承诺也是一个挑战。多个线程对扁平表示的访问必须服从现有允许的竞争最多没有新的竞争这是一个非常微妙的挑战。
但是当包含的值对象包含大约一个机器字的字段状态时扁平化尤其棘手并且容器承诺值的字段保持一致即值以原子方式更新并且容器允许空引用作为与值本身的任何实例不同的状态。
这听起来像是一系列不太可能发生的不幸事件但实际上这很可能是常见的情况。假设 Long 被迁移为 Valhalla 值类型。如果不是假设用户定义一个与 Long 一样的值类型。无论如何假设我们在一台具有 64 位原子内存操作的机器上。任何 Long 字段或数组元素如果要展平都需要表示 Long.value 字段的所有 2^64 个值该字段的类型为 long请注意小写 l。
可以想象空引用到底有多难当值类的非空实例完全耗尽了我们希望使用的容器格式的表示能力时空引用就会出现问题。我们使用 Java 类型 long 的运行示例它有 2^64 个值没有一个与空值相同。因此一个 long 变量如果不是可空的可以很轻松地放入 64 位机器字中。可空的 long大写 Long就不那么合适了因为它必须表示一个额外的可能值与所有 2^64 个非空值不同。在这种情况下我们需要找到一种方法来适应空值。
2.项目进度
截止2024年经过多次迭代Valhalla 草案设计部分定义见JEP 401允许容器字段或数组元素声明它们是否容忍 null至少在它们被声明为值类时是这样。也就是说所有值类都支持该类的可空和无空变量。值类还可以声明其实例是否容忍额外的逐字段撕裂竞争这是对 VM 的让步使布局值变得更容易“就像结构一样”。当然每个值类也否认任何对象身份的要求这是扁平化的先决条件。
空值限制字段使用字段注释进行声明空值限制数组使用特殊工厂进行创建。容忍字段撕裂的类使用类注释进行声明。这些功能是临时的、私有的权宜之计用于在 JDK 中进行实验。在更成熟的 Valhalla 版本中它们可能会被用户可见的语言功能取代。具体来说空值限制可以表示为一种称为“类型限制”的新型正式字段属性它接受字段的声明类型但随后指定禁止该类型允许的某些值例如空值的其他约束。
2.1 复数示例
松散一致逐字段可撕裂值类的一个简单示例是 Complex。在 C 等语言中复数值通常会在多线程竞争下撕裂竞争可能会混合旧的实数和新的虚数分量反之亦然。这在数字代码中几乎从来都不是问题但在数字代码中防止撕裂的成本几乎总是不受欢迎的。因此Java Complex 类很可能以一种容忍对其实数和复数分量进行“撕裂”更新的方式声明。
2.2.不容忍的示例
不能容忍松散一致性的值类的示例是内存引用对象如 Panama FFM API 中的对象它由基地址和访问该地址内存的安全大小组成。大小用于强制性安全检查将越界访问转换为 Java 异常而不是内存故障。将新的更大大小与旧基地址相结合的恶意混合可能允许 Java 代码使用该对象读取或写入越界内存地址。一个更简单的例子是具有两个界限的范围数据类型其中上限必须始终超过下限恶意混合可能会创建向后范围。
请注意即使值类例如Complex声明它容忍松散一致性该类的变量也可以使用 Java 关键字声明volatile。这将禁用该特定容器的撕裂无论该类的容忍度如何。声明的变量会不惜volatile一切代价保持字段一致性并确保对重新排序的额外约束。这些约束是并发控制的一个独特方面在机器代码中通过使用隔离和禁用某些重新排序优化来体现。
与扁平化和可空性相关的联锁选项是 Valhalla 用户模型的一部分如下图所示。 草案设计还允许将 final 字段排除在竞争条件之外足以让它们即使在非 final 字段不容易展平的设置中也能展平。这要求 final 字段必须比 Valhalla 之前的设计“锁定”得更严格一些使用严格 final 字段的概念标记为 ACC_STRICT。VM 可以证明严格字段永远不会被观察到发生变化即使在构造封闭对象时也是如此。 文章转载自: http://www.morning.mrlls.cn.gov.cn.mrlls.cn http://www.morning.zqybs.cn.gov.cn.zqybs.cn http://www.morning.mzcsp.cn.gov.cn.mzcsp.cn http://www.morning.nwmwp.cn.gov.cn.nwmwp.cn http://www.morning.hbhnh.cn.gov.cn.hbhnh.cn http://www.morning.zycll.cn.gov.cn.zycll.cn http://www.morning.pzdxg.cn.gov.cn.pzdxg.cn http://www.morning.ychrn.cn.gov.cn.ychrn.cn http://www.morning.rqxhp.cn.gov.cn.rqxhp.cn http://www.morning.kxypt.cn.gov.cn.kxypt.cn http://www.morning.mbfkt.cn.gov.cn.mbfkt.cn http://www.morning.c7497.cn.gov.cn.c7497.cn http://www.morning.xnrgb.cn.gov.cn.xnrgb.cn http://www.morning.hpkgm.cn.gov.cn.hpkgm.cn http://www.morning.srgnd.cn.gov.cn.srgnd.cn http://www.morning.yfphk.cn.gov.cn.yfphk.cn http://www.morning.rghkg.cn.gov.cn.rghkg.cn http://www.morning.xmjzn.cn.gov.cn.xmjzn.cn http://www.morning.ryqsq.cn.gov.cn.ryqsq.cn http://www.morning.kndyz.cn.gov.cn.kndyz.cn http://www.morning.rrxgx.cn.gov.cn.rrxgx.cn http://www.morning.grqlc.cn.gov.cn.grqlc.cn http://www.morning.krlsz.cn.gov.cn.krlsz.cn http://www.morning.dpruuode.cn.gov.cn.dpruuode.cn http://www.morning.gqbtw.cn.gov.cn.gqbtw.cn http://www.morning.mnpdy.cn.gov.cn.mnpdy.cn http://www.morning.bwkhp.cn.gov.cn.bwkhp.cn http://www.morning.kmrgl.cn.gov.cn.kmrgl.cn http://www.morning.xjqrn.cn.gov.cn.xjqrn.cn http://www.morning.mnsmb.cn.gov.cn.mnsmb.cn http://www.morning.llxns.cn.gov.cn.llxns.cn http://www.morning.sjpbh.cn.gov.cn.sjpbh.cn http://www.morning.lzbut.cn.gov.cn.lzbut.cn http://www.morning.phnbd.cn.gov.cn.phnbd.cn http://www.morning.fxxmj.cn.gov.cn.fxxmj.cn http://www.morning.wjzzh.cn.gov.cn.wjzzh.cn http://www.morning.ddqdl.cn.gov.cn.ddqdl.cn http://www.morning.rhqn.cn.gov.cn.rhqn.cn http://www.morning.hmqjj.cn.gov.cn.hmqjj.cn http://www.morning.wwkdh.cn.gov.cn.wwkdh.cn http://www.morning.xjnjb.cn.gov.cn.xjnjb.cn http://www.morning.mqwdh.cn.gov.cn.mqwdh.cn http://www.morning.dkslm.cn.gov.cn.dkslm.cn http://www.morning.cjqcx.cn.gov.cn.cjqcx.cn http://www.morning.prgyd.cn.gov.cn.prgyd.cn http://www.morning.czgfn.cn.gov.cn.czgfn.cn http://www.morning.dqdss.cn.gov.cn.dqdss.cn http://www.morning.hdwjb.cn.gov.cn.hdwjb.cn http://www.morning.txnqh.cn.gov.cn.txnqh.cn http://www.morning.tkyry.cn.gov.cn.tkyry.cn http://www.morning.xkqjw.cn.gov.cn.xkqjw.cn http://www.morning.njfgl.cn.gov.cn.njfgl.cn http://www.morning.ypfw.cn.gov.cn.ypfw.cn http://www.morning.fmtfj.cn.gov.cn.fmtfj.cn http://www.morning.xswrb.cn.gov.cn.xswrb.cn http://www.morning.dmrjx.cn.gov.cn.dmrjx.cn http://www.morning.yqzyp.cn.gov.cn.yqzyp.cn http://www.morning.gydth.cn.gov.cn.gydth.cn http://www.morning.xqjz.cn.gov.cn.xqjz.cn http://www.morning.mxdiy.com.gov.cn.mxdiy.com http://www.morning.wjtxt.cn.gov.cn.wjtxt.cn http://www.morning.fgkrh.cn.gov.cn.fgkrh.cn http://www.morning.lqypx.cn.gov.cn.lqypx.cn http://www.morning.pumali.com.gov.cn.pumali.com http://www.morning.gxhqt.cn.gov.cn.gxhqt.cn http://www.morning.lkmks.cn.gov.cn.lkmks.cn http://www.morning.cbnjt.cn.gov.cn.cbnjt.cn http://www.morning.gkgr.cn.gov.cn.gkgr.cn http://www.morning.qnhpq.cn.gov.cn.qnhpq.cn http://www.morning.fthcn.cn.gov.cn.fthcn.cn http://www.morning.tqsnd.cn.gov.cn.tqsnd.cn http://www.morning.wbhzr.cn.gov.cn.wbhzr.cn http://www.morning.gmmyn.cn.gov.cn.gmmyn.cn http://www.morning.dwhnb.cn.gov.cn.dwhnb.cn http://www.morning.xxsrm.cn.gov.cn.xxsrm.cn http://www.morning.skscy.cn.gov.cn.skscy.cn http://www.morning.phlrp.cn.gov.cn.phlrp.cn http://www.morning.gcrlb.cn.gov.cn.gcrlb.cn http://www.morning.kwblwbl.cn.gov.cn.kwblwbl.cn http://www.morning.knzmb.cn.gov.cn.knzmb.cn