V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
lewis89
V2EX  ›  程序员

我们是正经的技术内推交流群

  •  
  •   lewis89 · 2020-12-29 00:22:10 +08:00 · 4237 次点击
    这是一个创建于 1450 天前的主题,其中的信息可能已经有所发展或是发生改变。
    迫于今早新加入的一个小老弟的提问,https://club.perfma.com/question/2079981

    我又是 debug 又是反编译,总算是把那个问题给整明白了
    https://github.com/jonwinters/jmm-research

    另外关于 x64 的 lock 的语义,大家有兴趣上 Stack Overflow 看,
    中文区我 Google 了一下,基本没有人能写博客给整明白的。

    再次申明:我们是正经的技术内推交流群,希望有大佬加入讨论吹水,
    哪怕是偶尔指点一下研究方向,也是不胜感激。

    微信 ID: Y2hlbjExMjIwMDM3Cg==
    第 1 条附言  ·  2020-12-29 16:24:34 +08:00
    d3UzMDEzNTY4MQo=
    第 2 条附言  ·  2020-12-29 16:24:45 +08:00
    更新:d3UzMDEzNTY4MQo=
    52 条回复    2021-01-26 18:47:01 +08:00
    xlzy905
        1
    xlzy905  
       2020-12-29 11:32:37 +08:00
    频繁了
    lewis89
        2
    lewis89  
    OP
       2020-12-29 11:36:36 +08:00
    先 mark 一下,昨天一下子吸收了 100 多人
    xujihua
        3
    xujihua  
       2020-12-29 12:36:10 +08:00
    加不上了 拉一下可以嘛 微信 ID:bW9yYXRn
    sanwantian
        4
    sanwantian  
       2020-12-29 12:45:34 +08:00
    拉一下可以嘛 微信 ID:finalesanwantian
    lewis89
        5
    lewis89  
    OP
       2020-12-29 13:54:14 +08:00
    已拉
    x940727
        6
    x940727  
       2020-12-29 13:59:25 +08:00
    求拉 BASE64:WHU1NzIxMTcyMzU=
    banjueaz
        7
    banjueaz  
       2020-12-29 14:19:13 +08:00
    微信 ID:zb547856757 麻烦拉一下
    lewis89
        8
    lewis89  
    OP
       2020-12-29 14:30:17 +08:00
    6-7 已拉
    TheF00L
        9
    TheF00L  
       2020-12-29 14:49:50 +08:00
    昨天加就频繁了 微信 ID: dsdnnt 麻烦拉一下
    boblin
        10
    boblin  
       2020-12-29 15:52:43 +08:00
    前端可以么
    wdmm
        11
    wdmm  
       2020-12-29 16:06:11 +08:00
    求拉 Base64: endkMTE3ODQ2MTQ5MA==
    MrCard
        12
    MrCard  
       2020-12-29 16:09:46 +08:00
    求拉,微信号:TW96YXJrIA==
    lewis89
        13
    lewis89  
    OP
       2020-12-29 16:09:56 +08:00
    @wdmm #11 可以
    wr516516
        14
    wr516516  
       2020-12-29 16:12:46 +08:00
    楼主还帮忙拉嘛 d3I1MTY1MTY=
    mosliu
        15
    mosliu  
       2020-12-29 16:13:56 +08:00
    VX 同 id 求拉
    hun2008hun
        16
    hun2008hun  
       2020-12-29 16:18:08 +08:00
    这代码有 bug 呀,可见性的反义词是不一定可见,以前也看到人拿这代码来纠结 system.out ,完全不能理解在想什么
    zhanbiqiyu
        17
    zhanbiqiyu  
       2020-12-29 16:20:50 +08:00
    d3UzMDEzNTY4MQo=

    大家可以加我微信,我拉大佬们进群
    lewis89
        18
    lewis89  
    OP
       2020-12-29 16:24:19 +08:00
    @boblin #10 都可以,我可能也会求助一些前端知识
    toma77
        19
    toma77  
       2020-12-29 16:24:47 +08:00
    求啦 微信号:bHhzdW5iaW4=
    lewis89
        20
    lewis89  
    OP
       2020-12-29 16:33:00 +08:00
    @hun2008hun #16 你去反编译看看就知道了,我研究的本来就是为什么 DEMO1 会在那里死循环,从 GDB 反汇编来看 主线程就是读不到 num 的最新值,至于为什么这样 我也不清楚,但是后面的 lock 指令 确确实实有内存栅栏的作用
    lewis89
        21
    lewis89  
    OP
       2020-12-29 16:36:51 +08:00
    @hun2008hun #16 纠结 System.out ? System.out 本身在 JIT 下也是有一个 lock 指令生成的,刚好就是这个 lock 之类充当了内存栅栏
    lewis89
        22
    lewis89  
    OP
       2020-12-29 16:37:46 +08:00
    Cowhitewhite
        23
    Cowhitewhite  
       2020-12-29 16:38:05 +08:00
    求拉:Y293aGl0ZXdoaXRl
    cnzjl
        24
    cnzjl  
       2020-12-29 16:52:21 +08:00
    求拉 R2xhZE1vbnN0ZXI=
    hun2008hun
        25
    hun2008hun  
       2020-12-29 17:13:30 +08:00
    @lewis89 因为 demo1 有 bug,而且严谨说不一定死循环,只是你的 cpu 是这样。 第二个问题:lock 的话要不把 sleep(1000)去掉再跑下?
    lewis89
        26
    lewis89  
    OP
       2020-12-29 17:30:20 +08:00
    @hun2008hun #25 我管它有没有 bug? 只要是代码 确实有人会这么想 也这么犯傻用过,我就去查问题出在哪里就好了,我 JDK8 在树莓派上就没这个事情,你去掉 sleep(1000)又要为什么,它这个本来就是要循环去读,主线程循环 10 秒钟后还是读不到最新的值,那又是为什么。
    只有用 lock 才能读到,lock 本身就是有内存栅栏的特性,我早就知道这个特性,这个东西只是验证 告诉你怎么一回事。
    lewis89
        27
    lewis89  
    OP
       2020-12-29 17:31:32 +08:00
    @hun2008hun #25 而且我在很多库的代码里面都看到有人用 volatile 去做可见性的同步,但同时并未使用 happen-before 语义
    junziyangyang
        28
    junziyangyang  
       2020-12-29 18:18:21 +08:00 via iPhone
    求拉 feng-junzi
    HAluelue
        29
    HAluelue  
       2020-12-30 09:08:33 +08:00
    求拉 andyis1iin
    GunsRose
        30
    GunsRose  
       2020-12-30 09:16:38 +08:00
    求拉 songtao22
    will2zuo
        31
    will2zuo  
       2020-12-30 10:12:34 +08:00
    求拉 zz546398578
    young1lin
        32
    young1lin  
       2020-12-30 13:54:35 +08:00
    使用 System.out 会导致锁粗化的。。。你可以看看极客时间的专栏《 Java 并发编程实战》有一章的评论里面就说过,我记得是日志打印的那一章。
    lewis89
        33
    lewis89  
    OP
       2020-12-30 13:57:51 +08:00
    @young1lin #32 这个问题跟锁粗化没有关系,而是 lock 的语义 有内存栅栏的作用
    young1lin
        34
    young1lin  
       2020-12-30 16:00:58 +08:00
    @lewis89 我看错了,我是🐷,我就看到那个 monitorexit 了
    lewis89
        35
    lewis89  
    OP
       2020-12-30 16:24:55 +08:00
    @young1lin #34 monitorexit 下面的实现比较复杂 每个平台都不一样
    ezksdo
        36
    ezksdo  
       2021-01-23 14:40:33 +08:00
    原文里就有答案,能扯这么多。有 lock 就全局可见了?都锁的不是一个位置。
    lewis89
        37
    lewis89  
    OP
       2021-01-23 14:53:46 +08:00
    @ezksdo #36 哈,你不想研究就算了,不要瞎批评,我还真就告诉你 X86 有 lock 就能保障可见性 好吗? 跟锁不锁一个位置没有任何关系
    lewis89
        38
    lewis89  
    OP
       2021-01-23 14:55:34 +08:00
    @ezksdo #36 相同的语义 还有 mfence 会强制其它 CPU 刷写 write buffer
    lewis89
        39
    lewis89  
    OP
       2021-01-23 15:03:17 +08:00
    @ezksdo #36 请问 mfence MESI TSO NUMA 你了解几个? 你了解过了 再来批评也不迟
    ezksdo
        40
    ezksdo  
       2021-01-23 15:55:07 +08:00 via iPhone
    推荐你用 jitwatch 吧,看你 gdb 用得也费劲。这里就是 jit 优化,而打印函数有副作用,没有优化
    ezksdo
        41
    ezksdo  
       2021-01-23 15:56:39 +08:00 via iPhone
    你也不想想,不加 volatile 他就永远不写回内存吗?
    lewis89
        42
    lewis89  
    OP
       2021-01-23 16:05:15 +08:00
    @ezksdo #41 我不知道 JVM 为什么会有这种优化,jitwatch 又不能 debug,我在 gdb 里面 已经看过了,那个内存地址读出来的值就是 0 ,无论多久都是 0,至于是主线程 读到的是未失效的 L1/L2 cache,还是什么,我就不在乎了
    lewis89
        43
    lewis89  
    OP
       2021-01-23 16:16:27 +08:00
    @ezksdo #41

    https://www.zhihu.com/question/263528143/answer/270308453

    而且你从这个原答案里面可以看到
    lock addl $0x0, (%rsp); 对 rsp 指针 + 0 操作是毫无意义的,rsp 是栈顶指针
    lock 是让 cache 失效,保证可见性,如果可见性没有保证,代码依旧会死循环

    而对 变量 i 加 volatile 属性 并没有使用 happen before
    lewis89
        44
    lewis89  
    OP
       2021-01-23 16:25:46 +08:00
    @ezksdo #41 关键是我那个死循环的地方 你有留意看了没有,跟激进编译半毛钱关系都没有



    第一步要通过 R15 寄存器 偏移 0x108 的位置去取值,

    第二步才是跟存放了 立即值 0 的 RAX 寄存器比较

    比较失败跳回第一步 ,这跟 JVM 激进优化有半毛钱关系? 分明就是 [R15 + 0x108] 寄存器的指针 取不到新的值
    ezksdo
        45
    ezksdo  
       2021-01-23 16:28:03 +08:00 via iPhone
    cache 以行为单位,打印函数有 lock 并不能导致 num 变量可见,写 volatile 就是 happens before volatile 读的,我不知道你说的使用是什么
    lewis89
        46
    lewis89  
    OP
       2021-01-23 16:35:51 +08:00
    @ezksdo #45 如果读写 volatie.. 都是在同一个线程里面, 又何来一个线程 对 另外一个线程 观测到的 happen before ?
    lewis89
        47
    lewis89  
    OP
       2021-01-23 16:38:06 +08:00
    @ezksdo #45 你要 A 线程 写了 volatile,另外一个 B 线程 后续去读 volatile,保障 B 线程能观测到 A 线程写 volatile 的事情都发生,这才算是 happen before
    lewis89
        48
    lewis89  
    OP
       2021-01-23 16:38:48 +08:00
    你要 A 线程 写了 volatile,另外一个 B 线程 后续去读 volatile,保障 B 线程能观测到 A 线程写 volatile 之前的事情都发生,这才算是 happen before
    lewis89
        49
    lewis89  
    OP
       2021-01-23 16:39:11 +08:00
    @ezksdo #45
    你要 A 线程 写了 volatile,另外一个 B 线程 后续去读 volatile,保障 B 线程能观测到 A 线程写 volatile 之前的事情都发生,这才算是 happen before
    lewis89
        50
    lewis89  
    OP
       2021-01-26 18:37:36 +08:00
    @ezksdo #45 我错了,我重新静态分析了一下,没错是 激进编译的问题

    lewis89
        51
    lewis89  
    OP
       2021-01-26 18:39:45 +08:00
    @ezksdo #45 这几天在读 JVM 的操作数栈,忽然明白了这块,字节码所有的操作方法没有立即数,是使用操作数栈 来完成的,然后重新静态分析了一下,确实是 JVM 激进编译的锅
    lewis89
        52
    lewis89  
    OP
       2021-01-26 18:47:01 +08:00
    @ezksdo #45 人外有人,山外有山,老哥有兴趣加个好友,相互交流一下吗
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5444 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 08:39 · PVG 16:39 · LAX 00:39 · JFK 03:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.