`
jimmee
  • 浏览: 539993 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

2. 伪共享(False Sharing)[转载]

阅读更多

作者:Martin Thompson  译者:丁一

缓存系统中是以缓存行(cache line)为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。最常见的缓存行大小是64个字节。当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。缓存行上的写竞争是运行在SMP系统中并行线程实现可伸缩性最重要的限制因素。有人将伪共享描述成无声的性能杀手,因为从代码中很难看清楚是否会出现伪共享。

为了让可伸缩性与线程数呈线性关系,就必须确保不会有两个线程往同一个变量或缓存行中写。两个线程写同一个变量可以在代码中发现。为了确定互相独立的变量是否共享了同一个缓存行,就需要了解内存布局,或找个工具告诉我们。Intel VTune就是这样一个分析工具。本文中我将解释Java对象的内存布局以及我们该如何填充缓存行以避免伪共享。



 
图 1.

图1说明了伪共享的问题。在核心1上运行的线程想更新变量X,同时核心2上的线程想要更新变量Y。不幸的是,这两个变量在同一个缓存行中。每个线程都要去竞争缓存行的所有权来更新变量。如果核心1获得了所有权,缓存子系统将会使核心2中对应的缓存行失效。当核心2获得了所有权然后执行更新操作,核心1就要使自己对应的缓存行失效。这会来来回回的经过L3缓存,大大影响了性能。如果互相竞争的核心位于不同的插槽,就要额外横跨插槽连接,问题可能更加严重。

Java内存布局(Java Memory Layout)

对于HotSpot JVM,所有对象都有两个字长的对象头。第一个字是由24位哈希码和8位标志位(如锁的状态或作为锁对象)组成的Mark Word。第二个字是对象所属类的引用。如果是数组对象还需要一个额外的字来存储数组的长度。每个对象的起始地址都对齐于8字节以提高性能。因此当封装对象的时候为了高效率,对象字段声明的顺序会被重排序成下列基于字节大小的顺序:

  1. doubles (8) 和 longs (8)
  2. ints (4) 和 floats (4)
  3. shorts (2) 和 chars (2)
  4. booleans (1) 和 bytes (1)
  5. references (4/8)
  6. <子类字段重复上述顺序>

(译注:更多HotSpot虚拟机对象结构相关内容:http://www.infoq.com/cn/articles/jvm-hotspot

了解这些之后就可以在任意字段间用7个long来填充缓存行。在Disruptor里我们对RingBuffer的cursor和BatchEventProcessor的序列进行了缓存行填充。

为了展示其性能影响,我们启动几个线程,每个都更新它自己独立的计数器。计数器是volatile long类型的,所以其它线程能看到它们的进展。

01 public final class FalseSharing
02     implements Runnable
03 {
04     public final static int NUM_THREADS = 4// change
05     public final static long ITERATIONS = 500L * 1000L * 1000L;
06     private final int arrayIndex;
07   
08     private static VolatileLong[] longs = new VolatileLong[NUM_THREADS];
09     static
10     {
11         for (int i = 0; i < longs.length; i++)
12         {
13             longs[i] = new VolatileLong();
14         }
15     }
16   
17     public FalseSharing(final int arrayIndex)
18     {
19         this.arrayIndex = arrayIndex;
20     }
21   
22     public static void main(final String[] args) throws Exception
23     {
24         final long start = System.nanoTime();
25         runTest();
26         System.out.println("duration = " + (System.nanoTime() - start));
27     }
28   
29     private static void runTest() throws InterruptedException
30     {
31         Thread[] threads = new Thread[NUM_THREADS];
32   
33         for (int i = 0; i < threads.length; i++)
34         {
35             threads[i] = new Thread(new FalseSharing(i));
36         }
37   
38         for (Thread t : threads)
39         {
40             t.start();
41         }
42   
43         for (Thread t : threads)
44         {
45             t.join();
46         }
47     }
48   
49     public void run()
50     {
51         long i = ITERATIONS + 1;
52         while (0 != --i)
53         {
54             longs[arrayIndex].value = i;
55         }
56     }
57   
58     public final static class VolatileLong
59     {
60         public volatile long value = 0L;
61         public long p1, p2, p3, p4, p5, p6; // comment out
62     }
63 }

结果(Results)

运行上面的代码,增加线程数以及添加/移除缓存行的填充,下面的图2描述了我得到的结果。这是在我4核Nehalem上测得的运行时间。




 
 
图 2.

从不断上升的测试所需时间中能够明显看出伪共享的影响。没有缓存行竞争时,我们几近达到了随着线程数的线性扩展。

这并不是个完美的测试,因为我们不能确定这些VolatileLong会布局在内存的什么位置。它们是独立的对象。但是经验告诉我们同一时间分配的对象趋向集中于一块。

所以你也看到了,伪共享可能是无声的性能杀手。

  • 大小: 24.2 KB
  • 大小: 7.7 KB
分享到:
评论

相关推荐

    Sharing.Big.Data.Safely.Managing.Data.Security.1491952121.epub

    Chapter 2. The Challenge: Sharing Data Safely Chapter 3. Data on a Need-to-Know Basis Chapter 4. Fake Data Gives Real Answers Chapter 5. Fixing a Broken Large-Scale Query Chapter 6. Fraud Detection ...

    【并发编程】 — 伪共享(False Sharing)底层原理及其解决方式

    1.2 缓存行的概念1.3 伪共享(False Sharing)的概念 + 其可能引发的性能问题2 如何避免伪共享 — 数据填充2.1 不使用数据填充时的效率验证2.2 手动进行数据填充的效率验证2.3 通过java8新特性@sun.misc.Contended...

    SAP.on.DB2.for.zOS.and.OS390.High.Availability.and.Performance.Monitoring.with.Data.Sharing

    SAP.on.DB2.for.zOS.and.OS390.High.Availability.and.Performance.Monitoring.with.Data.Sharing

    sss.rar_image sharing _sss_z

    一个名为“sss.rar_image sharing_sss_z”的文件引起了我们的关注,这不仅因为它的压缩格式和内容指向性,还因为其中可能蕴含的图像处理技术与共享机制。 从标题“sss.rar_image sharing_sss_z”中我们可以推测,...

    Video12.Demo2.PortSharing

    Video12.Demo2.PortSharing

    hour.csv“Bike Sharing”数据集

    “Bike Sharing”数据集,在不同情况(季节、月份、时间、假日、星期、工作日、天气、温度、体感温度、湿度、风速等)每个小时的租用数量。

    Java中的伪共享详解及解决方案.docx

    伪共享(False Sharing)是在多线程环境中出现的一种现象,特别是在涉及多核处理器的情况下更为显著。在现代计算机体系结构中,CPU缓存系统是以缓存行(Cache Line)为单位进行存储的。通常情况下,主流CPU的缓存行大小...

    VirtualHereUSB共享器.zip

    VirtualHereUSB共享器.zipVirtualHereUSB共享器.zipVirtualHereUSB共享器.zipVirtualHereUSB共享器.zipVirtualHereUSB共享器.zipVirtualHereUSB共享器.zipVirtualHereUSB共享器.zipVirtualHereUSB共享器....

    jxta-myjxta-2.5.zip_file sharing in chat_jxta 2.5 例子_jxta2.5.jar

    2. **文件共享**:在JXTA中,文件共享是通过文件服务实现的,它可以将文件分块并存储在不同的节点上,用户可以通过查询找到并下载所需文件。在myJXTA-2.5的示例中,文件共享功能可能涉及到文件的上传、下载、查找...

    RR.rar_Time sharing_quantum algorithm_round robin_rr ready queue

    It is designed especially for time-sharing systems. The ready queue is treated as a circular queue. The algorithm assigns a time slice(also called time quantum) to each process in the ready queue in ...

    Samba文件共享SambaFilesharing.apk

    windows访问ubuntu很简单, 先在ubuntu上设置共享目录即可, 鼠标右键点目录,选择sharing options, 够选share this folder,需要的话也可以够选下面的allow write 这时在windows的网络邻居中的网络中查找就能找到...

    P2P_file_sharing_code.rar_Find Files_VB 文件共享_sharing files

    标题 "P2P_file_sharing_code.rar_Find Files_VB 文件共享_sharing files" 提供了我们讨论的关键点:这是一个基于VB(Visual Basic)编程语言实现的P2P(点对点)文件共享客户端,它的主要功能是让用户能够搜索并...

    DesktopSharing:通过 windows 桌面共享 api 的桌面共享应用程序

    标题中的"DesktopSharing"指的是一个基于Windows桌面共享API开发的应用程序,它允许用户分享他们的桌面内容给其他人。在本文中,我们将深入探讨Windows桌面共享API的原理、使用C#编程语言实现桌面共享的方法,以及...

    easy.file.sharing.web.server.v6.9.rar.7z

    Easy File Sharing Web Server允许用户不需要任何附加的软件或服务就可以架设一个安全的、基于网页的P2P文件分享、传输系统。 除了HTML网页界面设计,Easy File Sharing Web Server还可以让你直接在自己的PC上快速架...

    Open_Thread-.rar_Time sharing_Von Neumann_open_open thread_opent

    对于传统的单核CPU计算机,多任务操作系统的实现是通过CPU分时(time-sharing)和程序并发(concurrency)完成的。即在一个时间段内,操作系统将CPU分配给不同的程序,虽然每一时刻只有一个程序在CPU中运行,但是...

    Kaggle共享单车数据分析 .pdf

    数据来自Kaggle的BikeSharing Demand预测项目,提供了华盛顿特区2011年1月1日至2012年12月31日的共享单车租赁数据。数据集分为train.csv和test.csv,train.csv包含了两年内每月1日至19日的租赁数据,test.csv包含了...

    Java 80 道面试题及答案.docx

    1. 伪共享(False Sharing): 伪共享是多线程系统中一个众所周知的性能问题,发生在不同处理器的上的线程对变量的修改依赖于相同的缓存行。 2. Busy Spin: Busy Spin 是一种在不释放 CPU 的基础上等待事件的技术,...

    Likz.Me - Photo Sharing-crx插件

    "Likz.Me - Photo Sharing-crx插件"是一款专为用户设计的网页截图和图片分享工具,主要针对英文用户群体。这款插件的核心功能在于帮助用户轻松捕获网页上的可视内容,无论是局部区域还是整个页面,都能进行快速、...

Global site tag (gtag.js) - Google Analytics