zl程序教程

您现在的位置是:首页 >  其它

当前栏目

有助于减少伪共享的@Contended注解

注解 共享 减少 有助于
2023-09-14 08:56:52 时间

原文链接 作者:Dave 译者:卓二妹 校对:丁一

详细描述看Aleksey Shipilev这封邮件 —— 我们期待@Contended已久。JVM会自动为对象字段进行内存布局。通常JVM会这样做:(a)将对象的域按从大到小的顺序排列,以优化占用的空间;(b)打包引用类型的字段,以便垃圾收集器在追踪的时候能够处理相连的引用类型的字段。@Contended让程序能够更明确地控制并发和伪共享。通过该功能我们能够把那些频繁进行写操作的共享字段,从其它几乎是只读或只有少许写操作的字段中分离开来。原则很简单:对共享内容进行读操作的代价小,对共享内容的写操作代价非常高。我们也可以将那些可能会被同一个线程几乎同时写的字段打包到一起。

一般而言,我们试图改变相关字段的位置,以使得coherency misses的发生次数降到最低。在简单的单线程环境中,那些在时间上紧挨在一起被访问的字段,空间上应该放置在相邻的位置以提升缓存局部性[1]。也就是,时间局部性应该决定着空间局部性。时间上在一起访问的字段应该放到空间上相邻的位置。我们说过,当多线程并发访问我们的字段的时候,我们必须小心翼翼地以避免伪共享和因coherence traffic导致过多的缓存失效。同样地,对于那些原本是分开的字段,但可能会被同一个线程同时写入相同的缓存行,我们会试图将这些字段聚集到一起。注意:如果我们想极度地降低单线程下的容量缺失[2],那么在并发环境中可能出现大量的coherency misses。在原生C/C++代码中,程序员都在使用能感知并发的(concurrency-aware)结构布局。@Contended也应在JAVA中提供同样的功能,虽然在本地代码中,绑定字段到偏移量发生在编译阶段,但在JAVA中发生在装载阶段。值得指出的是,在一般情况下,找不到一个同时适用于单线程和多线程环境的最优布局。理想布局问题本身就是一个NP难题。

理想情况下,JAVA虚拟机应该使用硬件的监控设施来检测出共享行为,并在程序运行中改变布局。这是有一定困难的,因为我们还没有好的办法为JVM提供有效的信息。提示:我们需要取消操作系统和管理程序的中间层。另外一个挑战是,原始字段的偏移量有在unsafe工具中使用,因此我们需要解决这个问题,可能是使用一个额外的中间层。

最后,众所周知final字段是只读的,因此,我还希望能够将它们打包到一起。

[1]:早在1968年,Denning.P就曾提出局部性原理:程序在执行时将呈现出局部性规律,即在一较短的时间内,程序的执行仅局限于某个部分;相应地,它所访问的存储空间也局限于某个区域。

http://baike.baidu.com/view/1656353.htm http://baike.baidu.com/view/3238191.htm

[2]:根据缓存缺失的原因,可以分为以下几个类型:

强制缺失(Compulsory Miss):任何数据在未被载入缓存前都会造成缓存缺失,必须先把数据从内存/上一级缓存载入当前缓存,才能继续工作。由此带来的缺失,称为强制缺失。 容量缺失(Capacity Miss):由于缓存容量小于内存/上一级缓存,使得数据不能全部载入缓存,由此带来的缺失,叫做容量缺失。 冲突缺失(Conflict Miss):缓存中,每个cache line(缓存中数据访问的最小单位)会对应多处内存。之前的内存访问刷新了cache line,由此导致的缺失,称为冲突缺失。
Java内存泄漏概念、造成原因及检测方式(全) 本身java有垃圾回收器GC,可以内存管理,但为什么还会造成内存泄漏(内存泄漏不等于内存溢出),内存泄漏在项目实战或者企业项目是不被允许,甚至在企业面试中也是常考的题型。
性能优化之@Contended减少伪共享 说到伪共享,就要说CPU缓存,我们程序执行时候信息会被保存到CPU缓存中 而这些缓存中的数据可能被多线程访问,假如一个线程还没处理完,另外一个线程 就对数据进行了修改,就会导致上一个线程发生幻读的情况,比如刚才看到a=1,然后准备a = a+1。 但是还没做,另外一个线程就先将a变成2了。导致了上一个线程计算后本来应该是a = 1 + 1,变成了a = 2 + 1 计算结果就不对了。
常识四堆外内存 常识系列,作为一名互联网门外汉的科普系列 堆外内存除了在像netty开源框架中,在平常项目中使用的比较少,在现前的项目中,QPS要求高的系统中,堆外内存作为其中一级缓存是相当有成效的。所以来学习一下,文中主要涉及到这三分部内容 1. 堆外内存是什么?与堆内内存的区别 2. 怎么分配,与GC的影响 3. 开源框架使用 这篇文章写到最后,发现还只是回答了开源框架OHC的Why not use ByteBuffer.allocateDirect()?
“伪共享”凌乱记 本文属于并发编程系列,通过之前的文章我们了解到了CPU中缓存行的概念。简单复习一下就是缓存行是CPU读写缓存的最小单位,一般是64字节。另外当前CPU共有三个级别的缓存,从距离CPU内核的由近及远分为是L1 Cache、L2 Cache、L3 Cache。基于这个背景知识,我今天继续来谈一下和缓存相关的另一大话题:Fasle Sharing!
Java对象引用四个级别(强、软、弱、虚) 最近,高级Java技术栈微信群中,有一些猿友在讨论JVM中对象的周期问题,有谈到引用的级别,现在为大家做个总结吧,虽然大多数公司并没有意识或者用到这些引用,但了解这些基本概念对熟悉整个垃圾回收机制和面试是非常有帮助的。
测试应该如何处理跟开发之间的“敏感”关系? 测试从业者,打交道最多的就是开发,而测试和开发之间的关系在行业内被称为‘天敌’。最近部门内有些产品线成员和开发同事在协作之间也是双方抱怨不断,为此形成此文,算是给大家一些思路参考。 **作为测试工程师,你知道要怎么更好地来处理跟开发之间的关系么?其实对于存在这种所谓的‘敌对’关系,并不难理解。
中国科大实现两类不同量子资源间的相互循环转化 中国科学家提出量子相干性与量子关联之间的循环转化方法,并在光子系统中实验验证了该方案,相关研究成果在线发表在《物理评论快报》上。
前端优化系列 - 初始化的性能影响 数据表明,即使在资源有缓存的情况下,首次访问页面的耗时也是非首次访问的两倍。为什么首次访问会这么耗时呢?本文详细分析页面首次访问耗时的原因。
ali清英 方腾飞,花名清英,英文名kiral,并发编程网创始人,支付宝技术专家,《Java并发编程的艺术》作者。