Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java内存模型:编译器重新排列代码行_Java_Memory_Memory Model - Fatal编程技术网

Java内存模型:编译器重新排列代码行

Java内存模型:编译器重新排列代码行,java,memory,memory-model,Java,Memory,Memory Model,众所周知,Java语言允许编译器重新排列已编译代码的行,只要重新排序对代码语义没有影响。但是,编译器只需要关心从当前线程看到的语义。如果这种重新排序影响多线程情况下的语义,通常会导致并发问题(内存可见性) 我的问题: 允许编译器使用这个freedm实现了什么?编译器真的有可能通过重新排列代码来生成效率更高的代码吗?我还没有看到这方面的实际案例。我有时觉得,这可能带来的并发风险远远超过了好处(如果有的话) 程序员有没有办法告诉编译器不要这样重新排列行?我知道使用同步原语可以有效地处理重新排列的副作

众所周知,Java语言允许编译器重新排列已编译代码的行,只要重新排序对代码语义没有影响。但是,编译器只需要关心从当前线程看到的语义。如果这种重新排序影响多线程情况下的语义,通常会导致并发问题(内存可见性)

我的问题:

  • 允许编译器使用这个freedm实现了什么?编译器真的有可能通过重新排列代码来生成效率更高的代码吗?我还没有看到这方面的实际案例。我有时觉得,这可能带来的并发风险远远超过了好处(如果有的话)

  • 程序员有没有办法告诉编译器不要这样重新排列行?我知道使用同步原语可以有效地处理重新排列的副作用,但我想问的是,是否有任何直接的方法(编译器选项)可以关闭此功能


  • 重新排列字节码的过程由JIT(即时编译器)管理。您可以使用以下选项停止它的运行:

    -Djava.compiler=NONE
    

    请参阅此处的更多信息:

    Java C编译器几乎没有进行任何优化

    JIT本机编译器可以在内存排序出现问题时对指令重新排序。但是,CPU也可以重新排序具有相同效果的指令和内存更新

    允许编译器使用这个freedm实现了什么

    主要的好处是代码的可移植性。您提供的保证越多,确保每个平台都能做到这一点就越困难

    通过允许CPU在可能的时候执行指令,而不是按照严格的顺序执行指令,性能也有了显著的提高

    编译器真的有可能通过重新排列代码来生成效率更高的代码吗

    对。但CPU所做的重新排序更为重要

    我还没有看到这方面的实际案例。我有时觉得,这可能带来的并发风险远远超过了好处(如果有的话)

    程序员有没有办法告诉编译器不要这样重新排列行

    这就是为什么要使用诸如
    volatile
    synchronized
    块和
    锁等内存屏障。当您使用这些工具时,您可以获得线程安全保证

    我知道使用同步原语可以有效地处理重新排列的副作用,但我想问的是,是否有任何直接的方法(编译器选项)可以关闭此功能

    您可以关闭JIT,但大多数重新排序都是由CPU完成的,因此不会有多大效果

    避免更新的重新排序是线程安全问题的一小部分(其最大的问题是不明确且很少发生,这使得测试变得困难),一旦您编写了线程安全代码,这一问题就会得到缓解

    编译器真的有可能通过重新排列代码来生成效率更高的代码吗

    哦,是的

    现代计算机体系结构中的一个事实是内存是主要的性能瓶颈。CPU执行寄存器到寄存器指令的速度比它对主存的读写速度快很多倍。这就是为什么高性能芯片有2到3级的内存缓存。此外,典型的CPU使用流水线允许多条指令同时执行

    为了使具有这些属性的CPU获得最大的性能,编译器(以及CPU本身)需要能够对指令进行重新排序,以充分利用内存带宽,并保持流水线的满。本机代码还需要能够使用保存在寄存器中的值(变量),并尽量减少使用等待内存写入传播到主存的内存屏障指令。这些仅允许(在Java中),因为Java内存模型允许重新排序

    注意:我们这里讨论的是一个显著的加速:可能是3到5倍的加速


    如果您想了解具体数量,请使用实例变量密集型应用程序并重写它,以便所有实例变量都是
    易失的
    。(这将减少重新排序的范围,并导致所有读写都进入内存。)然后根据修改后的版本对原始应用程序的性能进行基准测试。

    这不会停止CPU重新排序指令。;)而且它会让你的程序运行非常慢,所以这不是一个对任何生产使用都有用的选项。