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

False Sharing 伪共享 – 译

    博客分类:
  • java
阅读更多

 

原文地址:http://coderbee.net/index.php/basis/20131110/566

翻译自:http://mechanical-sympathy.blogspot.com/2011/07/false-sharing.html

伪共享

内存在缓存系统里是以缓存行为单位存储的。缓存行是大小为2的整数幂的连续字节,典型是32-256字节。最普遍的缓存行大小是64字节。伪共享是 个术语,用于当多个线程不知不觉地相互影响对方的性能,在修改使用相同缓存行的依赖变量时。缓存行上的写冲突是并行执行线程在SMP(对称多处理器 )系统上获得伸缩性的单一最大制约因素。我已听到伪共享被描述为无声的性能杀手,因为在查看代码时,它非常不明显。

为了达到按线程数量的线性伸缩性,我们必须确保没有两个线程写同一个变量或同一个缓存行。两个线程写同一个变量可以在代码层面跟踪到。为了知道独立 变量是否共享同一个缓存行,我们需要知道内存布局,或者让工具告诉我们。 Intel VTune是这样的一个分析工具。在这篇文章,我将解释Java对象的内存布局和如何通过填充缓存行来避免伪共享。

false-sharing
上图展示了伪共享的问题。线程A允许在Core 1,想更新变量X,运行在Core 2的线程想更新变量Y。不幸的是这两个热门变量属于同一个缓存行。每个线程将竞争缓存行的所有权,这样它们可以更新它。如果Core 1获得所有权,缓存子系统需要作废Core 2对应的缓存行。当Core 2获得所有权并执行它的更新,Core 1 将被告诉去作废它的缓存行拷贝。这将来来回回往返让L3缓存极大影响性能。如果竞争的Core处于不同的sockets,那么需要额外的跨Socket互 连,这个问题将更加恶化。

Java 内存布局

对于HotSpot JVM,所有对象都有一个2-字(world)的头。第一个是“标记(mark)”字,有24比特位用于哈希码和8比特位用于标记,例如锁状态,或交换用 于锁对象。第二个字是指向对象所属类的引用。数组有额外的字用于数组的大小。每个对象对齐到8字节的粒度边界,为了性能。因而为了更高效填充,对象的字段 将被重排序,从声明的顺序到下面的基于字节大小的顺序:

  1. doubles (8) and longs (8)
  2. ints (4) and floats (4)
  3. shorts (2) and chars (2)
  4. booleans (1) and bytes (1)
  5. references (4/8)
  6. <repeat for sub-class fields>

(译注:上面小括号里的数字表示占用的字节数。)

有了这些知识,我们可以用7个long在任意字段之间填充缓存行。在Disruptor里,我们在RingBuffer游标和BatchEventProcessor序号器周围填充缓存行。

为了展示性能影响,让我们用一些线程各自更新自己独立的计数器。这些计数器将是volatile修饰的long,这样将可以看到他们的进展。

public final class FalseSharing
    implements Runnable
{
    public final static int NUM_THREADS = 4; // change
    public final static long ITERATIONS = 500L * 1000L * 1000L;
    private final int arrayIndex;

    private static VolatileLong[] longs = new VolatileLong[NUM_THREADS];
    static
    {
        for (int i = 0; i < longs.length; i++)
        {
            longs[i] = new VolatileLong();
        }
    }

    public FalseSharing(final int arrayIndex)
    {
        this.arrayIndex = arrayIndex;
    }

    public static void main(final String[] args) throws Exception
    {
        final long start = System.nanoTime();
        runTest();
        System.out.println("duration = " + (System.nanoTime() - start));
    }

    private static void runTest() throws InterruptedException
    {
        Thread[] threads = new Thread[NUM_THREADS];

        for (int i = 0; i < threads.length; i++)
        {
            threads[i] = new Thread(new FalseSharing(i));
        }

        for (Thread t : threads)
        {
            t.start();
        }

        for (Thread t : threads)
        {
            t.join();
        }
    }

    public void run()
    {
        long i = ITERATIONS + 1;
        while (0 != --i)
        {
            longs[arrayIndex].value = i;
        }
    }

    public final static class VolatileLong
    {
        public volatile long value = 0L;
        public long p1, p2, p3, p4, p5, p6; // comment out
    }
}

结果

运行上面的代码,逐渐增加线程数量和添加/移除缓存行填充,我得到的结果如下图所示。这是衡量运行在我的4核 Nehalem 上的测试持续时间。
false-sharing-test-result

伪共享的影响是清晰可见的,通过完成测试需要的时间的增加。没有缓存行竞争,我们可以达到接近按线程线性的扩展。

这不是一个完美等测试,因为我们不能确定VolatileLongs将布局到内存的哪里。他们是独立的变量。然而,经验显示同时分配的对象倾向于同地协作(co-located)。

现在你知道,伪共享是无声的性能杀手了。

另一个测试例子

这是来自作者的另一篇文章:http://mechanical-sympathy.blogspot.com/2011/08/false-sharing-java-7.html,由于相关,就放一起了。

看起来Java 7变得更聪明了,会消除或重排序未使用的字段,这重新引入伪共享。作者认为下面的代码是最可靠的:

import java.util.concurrent.atomic.AtomicLong;

public final class FalseSharing
    implements Runnable
{
    public final static int NUM_THREADS = 4; // change
    public final static long ITERATIONS = 500L * 1000L * 1000L;
    private final int arrayIndex;

    private static PaddedAtomicLong[] longs = new PaddedAtomicLong[NUM_THREADS];
    static
    {
        for (int i = 0; i < longs.length; i++)
        {
            longs[i] = new PaddedAtomicLong();
        }
    }

    public FalseSharing(final int arrayIndex)
    {
        this.arrayIndex = arrayIndex;
    }

    public static void main(final String[] args) throws Exception
    {
        final long start = System.nanoTime();
        runTest();
        System.out.println("duration = " + (System.nanoTime() - start));
    }

    private static void runTest() throws InterruptedException
    {
        Thread[] threads = new Thread[NUM_THREADS];

        for (int i = 0; i < threads.length; i++)
        {
            threads[i] = new Thread(new FalseSharing(i));
        }

        for (Thread t : threads)
        {
            t.start();
        }

        for (Thread t : threads)
        {
            t.join();
        }
    }

    public void run()
    {
        long i = ITERATIONS + 1;
        while (0 != --i)
        {
            longs[arrayIndex].set(i);
        }
    }

    public static long sumPaddingToPreventOptimisation(final int index)
    {
        PaddedAtomicLong v = longs[index];
        return v.p1 + v.p2 + v.p3 + v.p4 + v.p5 + v.p6;
    }

    public static class PaddedAtomicLong extends AtomicLong
    {
        public volatile long p1, p2, p3, p4, p5, p6 = 7L;
    }
}
1
0
分享到:
评论

相关推荐

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

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

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

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

    Samba文件共享SambaFilesharing.apk

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

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

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

    Easy File Sharing Web Server 7.2

    《Easy File Sharing Web Server 7.2:便捷的文件共享解决方案》 Easy File Sharing Web Server 7.2 是一款高效且易用的文件共享软件,它专为希望通过网络轻松进行文件上传与下载的用户设计。这款系统使得在互联网...

    八年级英语作文共享单车Bike_sharing

    【标题解析】:“八年级英语作文共享单车Bike-sharing”这篇标题表明了这是一篇针对初中生的英语写作,主题是关于共享单车(Bike-sharing)的现象及其影响,旨在锻炼学生的英语表达能力和对社会现象的理解。...

    P2P_file_sharing_code.rar_Find Files_VB 文件共享_sharing files

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

    Kaggle共享单车数据分析 .pdf

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

    ChatGPT Plus 共享方案。ChatGPT Plus _ OpenAI API sharing solution.zip

    ChatGPT Plus 共享方案。ChatGPT Plus _ OpenAI API sharing solution.zip

    Satori:Enlightened page sharing的ppt

    1. **Sharing-aware Block Devices**:当数据进入内存时,系统会在页缓存中立即检查共享机会,从而实现实时的共享检测。 2. **Repayment FIFO**:如果共享失败,系统会将页面返回给Guest,确保资源的有效分配。 ...

    并联电源的负载共享 load sharing

    并联电源的负载共享 load sharing,设计与介绍,多用在复杂通信、工业设备设计应用时,电源的备份,电源使用效率优化设计

    false-sharing

    虚假共享建造mvn clean packagedocker build -t false-sharing .跑docker run false-sharing

    基于Vue的Campus-Cloud-Sharing校园师生资料共享系统设计源码

    该项目为基于Vue框架构建的Campus-Cloud-Sharing校园师生资料共享系统,源码共计827个文件,涵盖了163个JavaScript文件、162个SVG图形文件、123个Java文件、79个GIF图像文件、53个CSS样式文件、47个Vue组件文件、47...

    secret-sharing, 一个秘密分裂秘密秘密秘密秘密共享方案的系统.zip

    secret-sharing, 一个秘密分裂秘密秘密秘密秘密共享方案的系统 秘密共享 一种用于分分和共享密钥( 就像比特比特 private 密钥)的图书馆,使用iframe共享方案。安装&gt;&gt;&gt; pip install secretsharing示例用

    手机网络USB共享驱动_for_XP

    android手机usb虚拟网卡驱动—手机虚拟网卡——Remote_NDIS_based_Internet_Sharing_Device 本文件为XP系统电脑连接手机后将手机的上网资源分享给电脑使用。 tips:使用手机流量给电脑上网可以大量消耗你的手机流量...

    智能算法:Gaining-sharing knowledge based algorithm基于知识获取共享的算法

    智能算法:Gaining-sharing knowledge based algorithm基于知识获取共享的算法

    最好的web文件分享工具Easy File Sharing Web Server

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

    VirtualHereUSB共享器.zip

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

    IBM PowerVM Virtualization Active Memory Sharing

    ### IBM PowerVM Virtualization Active Memory Sharing:深度解析与关键技术 #### 概览 IBM PowerVM Virtualization Active Memory Sharing(简称AMS)是IBM为提升Power Systems上虚拟化环境内存使用效率和灵活性...

Global site tag (gtag.js) - Google Analytics