精华内容
下载资源
问答
  • 编译原理

    2016-09-09 17:28:00
    编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法...学了编译原理之后的益处五点:一、可以更加容易的理解在一个语言种哪些写法是等价的,哪些...

    编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。 编译原理是计算机专业设置的一门重要的专业课程。编译原理可以说是一个计算机科学的缩影,你学习它更多的是去追寻程序设计语言的本质。
    学了编译原理之后的益处有五点:
    一、可以更加容易的理解在一个语言种哪些写法是等价的,哪些是有差异的。
    二、可以更加客观的比较不同语言的差异。
    三、更不容易被某个特定语言的宣扬者忽悠。
    四、学习新的语言是效率也会更高。
    五、其实从语言a转换到语言b是一个通用的需求,学好编译原理处理此类需求时会更加游刃有余。

    不学编译原理,可能永远给各种写编译器的人当奴隶,以为写程序只能按照他们设计的语言哲学来做。

    学习编译原理有三步: 
    1. 读书:龙虎鍄,把课后的题目会做的都做一遍。 
    2. 自己写一个toy compiler,编译一些简单的代码,尝试理解各部分之间如何整合。 
    3. 看LLVM的代码,试着在上面加一些东西。 

    转载于:https://www.cnblogs.com/TopHin/p/5857356.html

    展开全文
  • 编译原理随笔

    2016-09-10 22:13:00
    最近初步接触到了编译原理这门课程,通过老师提供的一些链接,以及课上的知识,对这门课了一些认识与了解。 编译原理旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法...

    最近初步接触到了编译原理这门课程,通过老师提供的一些链接,以及课上的知识,对这门课有了一些认识与了解。

    编译原理旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。从源语言提取需要的信息;把源语言翻译成目标语言;自动生成满足一定规范的文本...

    学习编译原理可以更加容易的理解在一个语言种哪些写法是等价的,哪些是有差异的可以更加客观的比较不同语言的差异,更不容易被某个特定语言的宣扬者忽悠,学习新的语言是效率也会更高。

    学过编译原理这门课程,各种文法、各种词法语法分析算法,非常消磨人的耐心和兴致;因此除了课上听讲,课外看书等途径之外,也应该多和人探讨交流,多在网站上查阅资料。将龙虎鲸三大宝书翻阅一下,也能提高学习效率。

     

    转载于:https://www.cnblogs.com/lawliet12/p/5860464.html

    展开全文
  • 编译原理第三版答案

    万次阅读 多人点赞 2018-12-19 21:21:23
    点此下载 ...2. 实现编译程序的主要方法有哪些? 答:主要有:转换法、移植法、自展法、自动生成法。 3. 将用户使用高级语言编写的程序翻译为可直接执行的机器语言程序有哪几种主要的方式? ...

     

    点此下载

     

     

    第一章

    1.典型的编译程序在逻辑功能上由哪几部分组成?

    答:编译程序主要由以下几个部分组成:词法分析、语法分析、语义分析、中间代码生成、中间代码优化、目标代码生成、错误处理、表格管理。

    2. 实现编译程序的主要方法有哪些?

    答:主要有:转换法、移植法、自展法、自动生成法。

    3. 将用户使用高级语言编写的程序翻译为可直接执行的机器语言程序有哪几种主要的方式?

    答:编译法、解释法。

    4. 编译方式和解释方式的根本区别是什么?

    答:编译方式:是将源程序经编译得到可执行文件后,就可脱离源程序和编译程序单独执行,所以编译方式的效率高,执行速度快;

    解释方式:在执行时,必须源程序和解释程序同时参与才能运行,其不产生可执行程序文件,效率低,执行速度慢。

     

     

     

    第二章

     

    1. 乔姆斯基文法体系中将文法分为哪几类?文法的分类同程序设计语言的设计与实现关系如何?

    答:1)0型文法、1型文法、2型文法、3型文法。

    2)

    2. 写一个文法,使其语言是偶整数的集合,每个偶整数不以0为前导。

    答:

             ZàSME | B

             Sà1|2|3|4|5|6|7|8|9

             Màe | D | MD

             Dà0|S

             Bà2|4|6|8

             Eà0|B

    3. 设文法G为:

    Nà D|ND

    Dà 0|1|2|3|4|5|6|7|8|9

    请给出句子123、301和75431的最右推导和最左推导。

    答:NÞNDÞN3ÞND3ÞN23ÞD23Þ123

             NÞNDÞNDDÞDDDÞ1DDÞ12DÞ123

             NÞNDÞN1ÞND1ÞN01ÞD01Þ301

             NÞNDÞNDDÞDDDÞ3DDÞ30DÞ301

             NÞNDÞN1ÞND1ÞN31ÞND31ÞN431ÞND431ÞN5431ÞD5431Þ75431

             NÞNDÞNDDÞNDDDÞNDDDDÞDDDDDÞ7DDDDÞ75DDDÞ754DDÞ7543DÞ75431

    4. 证明文法 SàiSeS|iS| i是二义性文法。

    答:对于句型iiSeS存在两个不同的最左推导:

             SÞiSeSÞiiSes

             SÞiSÞiiSeS

             所以该文法是二义性文法。

    5. 给出描述下面语言的上下文无关文法。

    (1) L1={anbnci |n>=1,i>=0 }

    (2) L2={aibj|j>=i>=1}

    (3) L3={anbmcmdn |m,n>=0}

    答:

    1. SàAB

    AàaAb | ab

    BàcB | e

    1. SàASb |ab

    Aàa | e

    1. SàaSd | A | e

    AàbAc | e

    6. 设计一个最简的DFA M,使其能够识别所有的被3整除的无符号十进制整数。

    答:

     

     

    7. 设计一个DFA,使其能够接受被4整除的二进制数。

    答:

     

    8. 写出表达下列各项的正则表达式。

    (1)二进制数且为5的倍数。

    (2)Σ={a,b,c},第一个a位于第一个b之前的字符串。

    (3)Σ={a,b,c},包含偶数个a的字符串。

    (4)Σ={0,1},不包含11子串的字符串。

     

    答:

    1

               可以先画出相应的有限自动机:

     

               添加新的开始状态S和终止状态T:

     

     

               根据以上自动机,列出以下方程:

    ① S=A

    ② A=0A+1B+T

    ③ B=0C+1D

    ④ C=0E+1A

    ⑤ D=0B+1C

    ⑥ E=0D+1E

    解以上方程组:

    ⑥Þ E=1*0D              

    ②Þ A=0*1B+0*T

    ⑥代入④Þ C=01*0D+1A

    ⑤代入④Þ C=01*00B+01*01C+1A

            Þ C=xB+yA

            其中x=(01*01)*01*00  y=(01*01)*1

    ⑤代入③Þ B=0C+10B+11C

            Þ B=(0|11)C+10B

            Þ B=(10)*(0|11)C

    将C=xB+yA代入上式Þ B=uB+vA

                       Þ B=u*vA

                       其中u=(10)*(0|11)x  v=(10)*(0|11)y

    将B=u*vA代入②Þ A=0*1u*vA+0*T

                   Þ A=(0*1u*v)*0*T

    将A代入①Þ S=(0*1u*v)*0*T

    串(0*1u*v)*0*即为所求。

    (2)该题目理解为:至少有一个a和一个b,且a出现在b的前面(可以有间隔),则答案为:

           c*a(a|c)*b(a|b|c)*

    (3)((b|c)*a(b|c)*a)*(b|c)*               (a(b|c)*a | b | c)*

    (4)(0|10)*(1|e)

     

     

     

    第三章

    1. 词法分析器的功能是什么?

    答:读源程序的字符序列,逐个拼出单词,并构造相应的内部表示TOKEN;同时检查源程序中的词法错误。

    1. 试分析分隔符(空格、跳格及回车等)对词法分析的影响。

    答:空格、跳格、回车等分隔符号对词法分析不起作用,可以删除。但是回车符号可以用于错误定位,所以在删除回车符号前需要统计回车的个数。

    1. 给出识别C语言全部实型常数的自动机。

    答:(+|-|e)([1-9][0-9]*|0)(.[0-9][0-9]*|e) (E(+|-|e)[0-9][0-9]*)

    4. 写出识别C语言中所有单词的LEX程序。

    答:

           L=[A-Z] | [a-z]

           D=[0-9]

           D1=[1-9]

           %%

           (L|_)(L|D|_)*  {return (1);}

           D1D*              {return (2);}

           +                     {return (3);}

           ……

     

     

     

    第四章

    1. 设有如下文法G[S]:

    SàaABbcd | e

    AàASd | e

    BàSAh | eC | e

    CàSf | Cg | e

    1. 求每个产生式的Predict集。
    2. 该文法是否为LL(1)文法?为什么?

    答:(1)

             Predict(SàaABbcd)={a}

             Predict(Sà e)={#,d,f,a,h }

             Predict(AàASd)={a,d}

             Predict(Aà e)={h,a,d,b,e}

             Predict(BàSAh)={a,d,h}

             Predict(Bà eC)={e}

             Predict(Bà e)={b}

             Predict(CàSf)={a,f}

             Predict(Cà Cg)={a,f,g}

             Predict(Cà e)={g,b}

             (2)由于Predict(AàASd)Ç Predict(Aà e)¹Æ,所以该文法不是LL(1)文法。

    2. 下列描述括号匹配的文法中,哪些是LL(1)文法?

    (1)    Sà(SS’ | e

             S’ à) | e

    (2)    Sà(S)S | e

    (3)    SàS(S)S | e

    (4)    Sà(S | S’

             S’à(S’) | e

    答:(1)不是,(2)是,(3)不是,(4)不是

    3. 已知文法G[E]:

    EàE+T | T

    TàT*F | F

    Fài | (E)

    请按递归下降法构造该文法的语法分析程序。

    答:求产生式的predict集合:

             predict(EàE+T)={i,(}

             predict(EàT)={i,(}

             predict(TàT*F)={i,(}

             predict(TàF)={i,(}

             由于文法中非终极符号E和T对应的产生式的predict集合的交集都不为空,所以该文法不满足自顶向下分析的条件,现对文法进行等价变换得到如下文法:

             EàTE’

             E’à+TE’ | e

             TàFT’

             T’à*FT’ | e

             Fài

             Fà(E)

             求新文法的predict集合:

             Predict(EàTE’)={(,i}

             Predict(E’à+TE’)={+}

             Predict(E’àe)={#,)}

             Predict(TàFT’)={i,(}

             Predict(T’à*FT’)={*}

             Predict(T’àe)={+,),#}

             Predict(Fài)={i}

             Predict(Fà(E))={(}

             由于以上文法中任意非终极符号对应的产生式的predict集合的交集都为空,所以满足自顶向下分析的条件,所以可以写出如下的递归下降语法分析伪代码:

             Void E()

             { if(tokenÎ{(,i}) {T();E’();}

              else Error();}

             void E’()

             { if(tokenÎ{+}) {Match(‘+’);T();E’();}

              else if(tokenÎ{#,)}) {;}

              else Error();}

             void T()

             { if(tokenÎ{i,(}) {F();T’();}

              else Error();}

             void T’()

             { if(tokenÎ{*}) {Match(‘*’);F();T’();}

              else if(tokenÎ{+,),#}) {;}

              else Error();}

             void F()

             { if(tokenÎ{i}) {Match(‘i’);}

              else if(tokenÎ{(}) {Match(‘(‘);E();Match(‘)’);}

              else Error();}

    4. 构造一个LL(1)文法G,它能识别语言L:

             L={w | w为字母表S上不包括两个相邻的1的非空串},其中S={0,1}。

    并证明你所构造的文法是LL(1)文法。

    答:Aà0E | 1F

             Bà0E | 1F

             Cà0E

             EàB | e

             FàC | e

             Predict(Aà0E)={0}

             Predict(Aà1F)={1}

             Predict(Bà0E)={0}

             Predict(Bà1F)={1}

             Predict(EàB)={0,1}

             Predict(Eàe)={#}

             Predict(FàC)={0}

             Predict(Fàe)={#}

             对任意非终极符号对应的产生式的predict集合的交集都为空,所以该文法是LL(1)文法。

    5. 已知文法G[A]为:

             AàaABe | a

             BàBb | d

    1. 试给出与G[A]等价的LL文法G’[A]。
    2. 构造G’[A]的LL(1)分析表并给出输入串aade#的分析过程。

    答:(1)所求G’[A]为:

             AàaA’              (1)

             A’àABe          (2)

    A’à e                (3)

             BàdB’              (4)

             B’àbB’            (5)

    B’à e                (6)

             Predict(AàaA’)={a}

             Predict(A’àABe)={a}

             Predict(A’àe)={#,d}

             Predict(BàdB’)={d}

             Predict(B’àbB’)={b}

             Predict(B’àe)={e}

             对任意非终极符号对应的产生式的predict集合的交集都为空,所以该文法是LL(1)文法。

    1. 分析表如下:

     

    a

    b

    d

    e

    #

    A

    (1)

     

     

     

     

    A’

    (2)

     

    (3)

     

    (3)

    B

     

     

    (4)

     

     

    B’

     

    (5)

     

    (6)

     

     

    aade#的分析过程如下

    分析栈

    输入流

    动作

    A#

    aade#

    替换(1)

    aA’ #

    aade#

    匹配

    A’ #

    ade#

    替换(2)

    ABe#

    ade#

    替换(1)

    aA’Be#

    ade#

    匹配

    A’Be#

    de#

    替换(3)

    Be#

    de#

    替换(4)

    dB’e#

    de#

    匹配

    B’e#

    e#

    替换

    e#

    e#

    匹配

    #

    #

    成功

     

     

     

     

    第五章(这章答案是错的)

    1. 设有下列文法:

             (1)    SàaA

                      AàAb

                      Aàb

             (2)    SàaSSb

                      SàaSSS

                      Sàc

             (3)    SàAS

                      Sàb

                      AàSA

                      Aàa

             (4)    SàcA

                      SàccB

                      BàccB

                      Bàb

                      AàcA

                      Aàa

    构造上述文法的LR(0)归约活前缀状态机,并给出LR(0)分析表。

    答:

             (1)

     

             (2)

     

     

             (3)

     

             (4)

     

     

    2. 设有下列文法:

             (1)    SàSaS | b

             (2)    SàbSb | cSc | b | c

             (3)    SàbSb | bSc | d

             (4)    SàaSb | bSa | ab

             (5)    SàSab | bR

                      RàS | a

             (6)    SàSAB | BA

                      Bàb

                      AàaA | B

             (7)    SàAaAb | BbBa

                      Bàe

                      Aàe

             (8)    AàaABe | Ba

                      BàdB | e

    说明上述文法是否为SLR(1)文法。若是,请构造SLR(1)分析表;若不是,请说明理由。

    答:

             (1)

     

             (2)

     

             (3)

     

     

             (4)

     

             (5)

     

             (6)

     

     

             (7)

     

             (8)

     

    3. 设有下列文法:

             SàaAd | bBd | aBe | bAe

             Aàg

             Bàg

    说明该文法是LR(1)文法,但不是LALR(1)文法。

    答:

     

     

    4. 设有下列文法:

             (1)    EàE+T | T

                      TàTF | T

                      Fà(E) | F* | a | b

             (2)    SàAa | bAc | dc | bda

                      Aàd

    说明上述文法是否为SLR(1)文法?是否为LALR(1)文法?并构造相应的分析表。

    答:(1)

     

     

             (2)

     

     

     

    5. 设有下列文法:

             LàMLb | a

             Màe

    说明上述文法是否为LR(1)文法,若不是,请说明理由。

    答:

     

     

     

     

    第六章

    1.试写出下列类型的内部表示:

      a.integer

      b.ARRAY [1..5] of RECORD i:integer; b:boolean END

      c.ARRAY [1..5] of RECORD a:ARRAY [1..10]; r:RECORD i,j:integer END END

      d. RECORD r: RECORD x,y:real END;a: ARRAY [1..10] of integer END

    2. 设当前层数为l,可用区距为101,且有下列程序段:

       CONST mm=333;nn=444;

       TYPE atype = ARRAY[1..10] OF real;

            rtype = RECORD i,j:integer END;

       VAR a,b:atype;

           x,y:real

       试写出各标识符的内部表示。

    3. 设当前层数和区距分别为l和off,且有函数说明首部:

       FUNCTION f(A:atype;VAR B:atype;VAR X:real):integer

       其中atype的定义见题5,试写出f的内部表示。

    4. 要求在下面括号中写上相应ℓ(层数)和区距(off)。

      ()()PROCEDURE g(A:atype;()()

    VAR B:atype;()()

    VAR X:real()())()().

    5. 给出下面C程序扫描到语句c=a+b+x时相应的全局符号表(采用顺序表结构)。

    main()

    {

    int a=0;

    float c=1.0;

    {

    float a=3.0;

    {

    float x=1.3;

    float b=0.3;

    }

    {

         int b=10;

         c=a+b+x;

    }

    }

    }

    6. 给出题1中程序扫描到语句c=a+b+x时相应的全局符号表(采用外拉链的散列表结构)。

    7. 根据标识符的作用域规则,分别给出图6.5的程序中,过程P、Q、R、S中有效的标识符。

     

     

    第七章

    1. 将算术表达式 (a+b)*(c+d)-(a+b+c) 翻译成四元式序列。
    2. 将下列语句翻译成四元式序列:
      1. IF  x>0  THEN x:=0 ELSE x:=1
      2. WHILE  x>0  DO  x:=x-1
      3. IF x>0  THEN  x:=x+1  ELSE

    IF x <0  THEN  x:=x+1  ELSE x:=x+1

      1. WHILE x > 0 DO

    WHILE y > 0 DO

    BEGIN y:=y-x; x:=x-1 END

    1. 给出如下程序段的四元式序列。(四元式的操作符可用自身代替)。其中A:Array of [1..10] of  integer。

      a:=1;

                     while a<=10 do

                       begin  if a<>b then

                                     A[a]:=A[b]+2;

                     else  a:=a+1; 

                     b:=b+1;

              end

    1. 试将FOR语句翻译成四元式序列。
    2. 试将UNTIL语句翻译成四元式序列。
    3. 试将CASE语句翻译成四元式序列。
    4. 试给出4、5、6题中翻译过程的语法制导程序。

     

     

    第八章

    1. 将下面的程序段划分为基本块并画出其程序流图。

             read(A);

             read(B);

             F:=1;

             C:=A*A;

             D:=B*B;

             if C<D goto L1;

             E:=A*A;

             F:=F+1;

             E:=E+F;

             write(E);

             goto L3;

    L1:    E:=B*B;

             F:=F+2;

             write(E);

             if E>100 goto L2;

             goto L3;

    L2:    F:=F-1;

             goto L1;

    L3:    write(E);

    2. 假设有如下语句序列,写出常表达式优化前和优化后的四元式中间代码。

             (1)    i:=1;                            (2)    a:=20;

             j:=i*(i+1);                   b:=a*(a+10);

             k:=2*(i+j);                           c:=a*b;

    3. 假设有如下语句序列或表达式,写出公共表达式优化前和优化后的四元式中间代码。

             (1)    x:=x*y+z; y:=x*y+z; z:=x*y+z;

             (2)    (a*b+c)/(a*b-c)+(c*b+a-d)/(a*b+c)

    4. 写出如下循环语句不变式外提后的四元式中间代码。

             while i<=100 do

                      begin        u:=A*B;

                                        m:=u*u;

                                        S:=S+m*m;

                                        i:=i+1;

                      end

    5. 写出下面循环语句不变式外提后的四元式中间代码,其中数组各下标的类型为1..10。

             while i<=100 do

                      begin        j:=1;

                                        while j<=100 do

                                                 begin        k:=1;

                                                                   while k<=100 do

                                                                            A[i][j][k]:=0;

                                                 end

                      end

     

     

     

    第九章

    1.过程活动记录包含哪些信息?各信息的作用?何时填写它们?

    2.下面是一个调用递归函数的Pascal程序

    program PP(input,output)

       VAR k:integer;

       FUNCTION F(n:integer):integer

       begin

           if n<=0 then F:=1

           else F:=n*F(n-1);

       end;

    begin

       k:=F(10);

      

    end.

    当第二次(递归地)进入F后,DISPLAY的内容是什么?当时整个运行栈的内容是什么?

    3.对于下面的程序:

    procedure P(X,Y,Z);

       begin

           Y:=Y+1;

           Z:=Z+X;

       end P;

    begin

       A:=2;

       B:=3;

       P(A+B,A,A);

       print A

    end

    当参数传递的办法分别为(1)传值;(2)传地址;(3)值-结果;(4)传名时,程序执行时输出的A分别是什么?

    4.应用Pascal语言的作用域规则,说明下面程序中的名字a和b的每一次出现所应用的声明。

    program a(input,output);

      procedure b(u,v,x,y:integer);

         var a:record a,b:integer end;

             b:reocrd b,a:integer end;

         begin

             with a do begin a:=u;b:=v end;

             with b do begin a:=x;b:=y end;

             writeln(a.a,a.b,b.a,b.b)

         end;

    begin

        b(1,2,3,4)

    end.

    5.为下面的C程序构造一个可能的运行时环境。

    int a[10];

    char *a=hello;

    int f(int i,int b[])

    {  int j=1;

       A: { int i=j;

            char c=b[I];

          }

        }

    void g(char *s)

    { char c[10];

      B: { int a[5];

           ... }

    }

    main()

    { int x=1;

      x=f(x,a);

      g(s);

      return 0; }

    (1)在进入函数f中的块A之后。

    (2)在进入函数g中的块B之后。

    6.Display表和静态链的作用是什么?试举一个程序例子,并考察其Display表和静态链的内容。

    7.过程参数的传递方式有几种?简述"传地址""传值"的实现原理。

     

     

     

    第十章

    • 什么叫指令的执行代价?
    • 寄存器分配的原则是什么?
    • 在剥夺寄存器的时候,应考虑哪些因素?什么时候一个变量可以主动释放它所占  用的寄存器?
    • 试写出程序段

    IF x > 0  THEN y:=y+1 ELSE

    IF x < 0  THEN y:=y-1

    的目标代码,其中的变量均为非形参实型变量。

    • 试写出程序段

    WHILE  x < y   DO

    BEGIN y :=y + 1;

        IF y > 0 THEN y :=y-x ELSE

        WHILE  y < 0 DO  y := y + x

    END

    的目标代码,其中变量均为非形参实型变量。

    • 试为FOR循环语句设计目标代码。
    • 试为REPEAT循环语句设计目标代码。
    • 试为CASE语句设计目标代码。

     

     

          

     

     

     

    展开全文
  • 第一章 1典型的编译程序在逻辑功能上由哪几部分组成 答编译程序主要由以下几个部分组成词法分析语法分析语义分析中间代码生成 中间代码优化目标代码生成错误处理表格管理 实现编译程序的主要方法有哪些 答主要有转换...
  • 1、多线程下 读写共享变量会有哪些问题 (原子性问题-线程切换导致的指令交错,可见性有序性问题-jit编译优化,cpu缓存优化) 2、解决这些问题的钥匙就是java内存模型,解决这些问题的手段–>掌握同步方法,如...

    永远的循环demo

     public class test {
            static   boolean stop = false; //停止标记
    
            public static void main(String[] args) throws InterruptedException {
                Thread t = new Thread(() -> {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    stop = true; // volatile 的写
                    System.out.println("thread: " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
    
                });
                System.out.println("start " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
                t.start();
                foo();
            }
    
            private static void foo() {
                while (true) {
                    boolean b = stop; // volatile 的读
                    if (b) {
                        break;
                    }
                }
                System.out.println("end " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
            }
        }
    

    执行在上面的这段代码,永远无法打印出“foo 方法中的 end” ,想要知道为什么,那么就必须要了解一下JMM

    加加减减出现了数据计算错误的情况demo

    
    

    第四种可能demo

    在这里插入代码片
    

    在揭秘出现这些问题的原因之前必须要明白两个事实1、写的代码未必就是实际运行的代码;2、代码的编写顺序未必就是实际的执行顺序;那为什么会这样呢?在多线程下在多线程下一个cpu总占用cpu是不合理的,任务调度器会让线程分时使用CPU,编译器以及硬件层面都会做成层层优化,提升性能
    了解一下编译器优化:
    编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序
    指令级并行的重排序。现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序;在保证代码最终执行结构一致的前提下对没有依赖的变量进行优化执行行顺序以获得更好的性能
    在这里插入图片描述

    了解一下指令流水线优化

    了解一下缓存优化

    这些都不是重点

    早期计算机的内存

    其实早期计算机中cpu和内存的速度是差不多的,但在现代计算机中,cpu的指令速度远超内存的存取速度,由于计算机的处理速度要远远的高于计算器的存储速度,处理结束等待存储完成显然这个是不合理的,所以不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲。将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中,这样处理器就无须等待缓慢的内存读写了,基于高速缓存解决了处理器与缓存之间的矛盾,但是这又引发了另外一个问题“缓存一致性”;借用网上的图
    在这里插入图片描述在多个处理器的计算器中每个计算器都有自己的一个高速缓存来解决处理快和存储慢的矛盾问题,但是因为他们又共同使用了同一块主内存多个高速缓存需要将自己的缓存内的内容同步到主内存导致了缓存一致性的问题;

    JMM

    JMM的规定

    java内存模型描述了java程序在多线程下各种变量(线程共享变量)的访问规则以及在JVM中将变量存储到内存和从内存中读取变量的这样的底层细节,JMM有这样的规定,所有的共享变量都存储在主内存,线程的工作内存保留了主内存的工作副本,线程对变量的所有的操作读和写必须在工作内存中完成,不能直接读写主内存的变量,不同线程之间也不能访问对方工作内存中的变量,线程中变量的同步在主内存中转完成,工作内存和主内存之间的关系如下
    在这里插入图片描述就是工作内存和主内存这样的关系,导致了多线程下读写共享变量会出现如如下接个问题1、原子性问题-线程切换导致的指令交错;2、可见性有序性问题-jit编译优化,cpu缓存优化;解决这些问题的关键在于java内存模型,解决的手段就是使用同步方法synchronized,ReentrantLock(解决原子性、可见性、有序性问题),volatile(解决可见性问题,有序性问题,思考为什么不能解决原子性问题)

    JMM的规则

    内存模型就是多线程下对共享变量的一组读写规则,符合这个套读写规则就可以保证多线程下的有序性 可见性 以及原子性
    规则一:RaceCondition规范 ,在多线程下 没有依赖关系的代码,在执行共享变量的读写操作(至少一个线程写),并不能保证以实际编码的顺序执行,这称为发生了竞态条件,想要保证执行顺序方法有很多比如加锁synchronization,使用volatile都可以,竞争是为了更好的性能,并不能因为麻烦而不去使用;

    假设有共享变量x,线程1执行
    			r.r1=y;
    			r.r2=x;
    		线程2执行
    			x=1;
    			y=1;
    
    	最终可能出现的结果可能是  r1==1,r2==0;
    执行的实际顺序可能如下:
    	y=1;
    	r.r1=y;
    	r.r2=x;
    	x=1;
    这就是说明了在多线程下,没有依赖关系的代码并不能保证代码的执行顺序
    

    规则2—>Synchronization Order 同步动作一个线程中代码的执行顺序
    若要保证多线程下的每个线程的执行顺序按编写顺序执行,那么必须使用Synchronization actions来保证,这些SA有1、lock,unlock-synchronization;2、volatile 方式读写共享变量可以保证可见性防止重排序,但不能保证原子性 ;3、varHandle方式读写变量jdk9引入;

    用volatile修饰共享变量 y,线程1执行
    		r.r1=y
    		r.r2=x;
    线程2执行
    		x=1;
    		y=1;
    最终的结果就不可能出现 r1==1而r2==0;
    

    Synchronization Order 同步动作保证的是一个线程中代码的执行顺序,并不是阻止多线程切换

    线程1执行
    	synchronized(lock){
    		r1=x; //1处
    		r2=x;//2处
    	}
    线程2执行
    	synchronized(lock){
    		x=1;
    	}
    

    并不是说 //1处与2处之间不能切换到线程2 ,只是即使切换到了线程2,因为线程2不能拿到lock锁,导致阻塞,执行权又会伦到线程1

    规则3–>Happens-Before规则,线程切换时代码的顺序和可见性
    若是变量读写时发生线程切换(比如线程1写入x,切换至线程2,线程2读取x)这些边界上如果有action1先于action2发生,那么代码可以按照确定的顺序执行,这种称为HappensBefre规则;可以理解为如果action1先于action2发生,那么action1之前的共享变量对象action2可见,并且按照代码的编写顺序执行;
    具体规则:
    1)线程的起懂和运行边界
    2)线程的结束和 join 边界
    3)线程的打断和得知打断边界
    4)unlock 与 lock 边界
    5)volatile write 与 volatile read 边界
    规则4–>安全发布
    若要安全的构造对象,并将其共享使用,需要使用final或者volatile修饰,并且避免this溢出的情况发生,使用stattic静态成员变量可以安全的发布,但是不属于懒加载的方式

    例如:
    	class student{
    		int  x1;
    		volatile int x2;         
    		public Holder ( int v){
    		}
    	}
    讲这个对象作为全局使用  
    Holder f;
    现在有两个线程一个去创建这个对象,一个去使用这个对象
    

    同步动作

    内存屏障

    一共有四种内存屏障,具体的实现与cpu的架构有关
    LoadLoad屏障:防止B的Load重排到A的Load之前
    
    		if(A){
    			LoadLoad
    			return B
    		}
    		read(A);
    		LoadLoad
    		read(B)
    		A==true时,再去获取B ,否则可能会因为重排的问题导致B的值相对A来说是过期的
    

    LoadStore屏障:防止B的写被重拍到A的读之前
    StoreStore屏障:防止A的写被重排到B的写的后面,

    		A=x;
    		storeStore
    		B=true;
    		意义在与B为true之前,其他的线程别想看到A的修改
    

    storeLoad(*)屏障:线程间的屏障,屏障前的改动都同步到主内存,屏障后的写获取到最新的数据,防止屏障前所有的写的操作被重新排序到屏障后的任何操作

    storeLoad屏障

    Volatile的本质

    定义一个变量共享变量x用volatile 修饰实际上加上了三组屏障,蓝色的代表线程1 ,红色的代表线程2;y=10是写的操作,在写操作x=10的时候,在前面加上storestore的屏障保证x=10前面的所有的写的操作无法越过屏障,后面加上storeload屏障保证之前的写不能够越过屏障之后的读也不能越过屏障,将数据写到主内存后面的获取到的是最新的数据;读取x变量的时候相当于加上了loadload和loadStore屏障,相当于r1=x之后的读操作不能越过屏障,r1=x之后的写不能越过屏障;加上了屏障之后就保证了代码的有序性,当然也有例外
    在这里插入图片描述在这里插入代码片

    volatile的有序性

    public class TestOrderingPartial {
        @JCStressTest
        @Outcome(id = {"0, 0", "1, 1", "0, 1"}, expect = Expect.ACCEPTABLE, desc = "ACCEPTABLE")
        @Outcome(id = "1, 0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "INTERESTING")
        @State
        public static class Case1 {
            int x;
            int y;
    
            @Actor
            public void actor1() {
                x = 1;
                y = 1;
            }
    
            @Actor
            public void actor2(II_Result r) {
                r.r1 = y;
                r.r2 = x;
            }
        }
    

    执行上面的代码可能会出现如下几种情况
    在这里插入图片描述出现 ‘00’,‘11’,“01”的情况,但是还有两种意外就是出现r1=1,r2=0的情况的情况,将用volatile修饰就不会出现r1=1,r2=0的情况,具体原理如下图,

     public static class Case1 {
            int x;
            volatile int y;
    
    

    在这里插入图片描述使用了volatile修饰了y,相当于在y=1前加了loadstore和storestore屏障,保证了前面读和写不可以越过屏障,后面加上了storeload保证了在上面的写不会排到后面,下面的读不会拍到前面,确保了线程切换时的有序性;

    在这里插入图片描述
    用volatile修饰了x,红色的线程中 r.r2=x,对于x的读限制了下面的代码的读和写无法越过屏障,但是限制不了r.r1=y向下走动,又由于内存屏障保证了线程内的代码的有序性(除了storeLoad对线程有影响保证有序),但是阻止不了线程间的指令切换如下图,先去读取r.r2=x;在去执行,这样照成了结果是r2=0,r1=1;

    在这里插入图片描述
    总结 :对于volatile的使用,volatile要用来修饰最先读取,最后写的变量;在同一个线程中volatile修饰的变量由于laodload与loadstore屏障的作用,保证了该变量的前面所有的读和写无法越过被修饰的变量(同一个线程中的有序性),由于storeoad屏障保证了将数据写到主内存,后续的读无法越过屏障,从而获取到最新的数据(切换线程时候的可见性);

    volalatile的使用场景

    volatile一般都是与cas一起使用保证原子性,可见性和有序性;
    atomicinterger

    第一个demo中添加volatile修饰解决可见性问题

     public class test {
            static  volatile  boolean stop = false; //停止标记
    
            public static void main(String[] args) throws InterruptedException {
                Thread t = new Thread(() -> {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    stop = true; // volatile 的写
                    System.out.println("thread: " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
    
                });
                System.out.println("start " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
                t.start();
                foo();
            }
    
            private static void foo() {
                while (true) {
                    boolean b = stop; // volatile 的读
                    if (b) {
                        break;
                    }
                }
                System.out.println("end " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
            }
        }
    

    解决可见性和线程内有序性的本质是在volatile修饰的变量做读的操作加上了内存屏障写的操作也加上了内存屏障

    Synchronized的本质

    在这里插入图片描述
    流程:synchronized本质是monotorcenter(根据lock对象找到monitor锁)和monitorexit(根据lock对象做锁的释放),底层的过程为thread1根据表面的java对象lock获取到monitor锁,实际上是系统提供的monitor锁只是根据这个对象找到系统提供的monitor锁的地址,根据monitor地址就可以找到monitor对象,当然首次访问就会创建这个monitor对象,Owner是锁的持有者,刚开始是空的,thread1进入monitor对象判断是否为空,如果是空的就持有owner,那么thread1就成为锁的持有者,thread2进入monitor对象的时候,发现owner中已经有thread1会尝试获取锁,如果尝试几次失败后就会进入EntryList,并且将线程状态改为阻塞状态,thread3进来同样会尝试获取到owner对象,如果失败就会进入EntryList中,并且EntryList是一个链表结构,这就是整个加锁的过程,解锁的过程,当thread1执行到monitorexit(lock)将owner置为空,这时唤醒thread2恢复运行,获取owner锁;

    有锁VS无锁

    synchronized悲关锁,如果一个线程执行时间比较长,那么其他线程都因为获取不到锁而陷入阻塞,阻塞的线程保存线程中代码如局部变
    量等的执行状态,当被唤醒的时候还需要将所有的代码状态全部都恢复,引起线程上下文切换,成本高;atomicInteger实现乐观锁并非加锁而是所有所有的线程全部都继续执行遇到锁的状态下“等”一会继续执行重复这个过程,减少了悲关锁引起的上下文切换成本高的问题,
    但是受到cup的核数限制,适用于于短频快的比如说计数器
    1、synchronized 更为重量,申请锁、锁重入都要发起系统调用,频繁调用性能会受影响
    2、synchronized 如果无法获取锁时,线程会陷入阻塞,引起的线程上下文切换成本高
    3、如果数据的原子操作时间较长,仍应该让线程阻塞,无锁适合的是短频快的共享数据修改操作主要用于计数 器、停止标记、或是阻塞前的有限尝试

    展开全文
  • webpack2 终极优化

    2021-01-01 19:13:14
    知道以上原理后我们还可以进一步优化:利用CommonsChunkPlugin提取出使用页面都依赖的基础运行环境。比如对于最常见的react体系你可以抽出基础库<code>react</code> <code>react-dom</code> <code>redux...
  • Code Compl 代码大全

    2011-05-26 12:09:22
     25.6 代码调整方法总结  推荐读物  算法和数据类型  关键点  第26章 代码调整方法  26.1 逻辑  在知道答案后停止判断  按照出现频率来调整判断顺序  相似逻辑结构之间的性能比较  用查找表替代复杂表达式...
  • webpack原理与实战

    2021-01-02 03:09:41
    代码分割优化 一个好的代码分割对浏览器首屏效果提升很大。比如对于最常见的react体系你可以 1. 先抽出基础库<code>react</code> <code>react-dom</code> <code>redux</code> <code>react-redux到一个单独的文件而...
  • 多种无阻塞加载JS的方法:<code>defer、<code>async、动态创建<code>script标签、使用XHR异步请求JS代码并注入到页面。 但更推荐的做法是使用<code>defer或<code>async。如果使用<code>defer或<code>async请...
  • 本书还有一个网站,上面本书额外的第12章“查询执行”、本书的所有代码及其他工具和脚本。  本书由知识丰富的资深专家和数位具有多年产品使用经验的讲师联手打造,是一本关于sql server工作原理的权威参考指南,...
  • 本书还有一个网站,上面本书额外的第12章“查询执行”、本书的所有代码及其他工具和脚本。  本书由知识丰富的资深专家和数位具有多年产品使用经验的讲师联手打造,是一本关于sql server工作原理的权威参考指南,...
  • 2.1.2变量有哪些类型 2.2如何使用变量 2.2.1如何使用整型变量 2.2.2如何使用浮点型变量 2.2.3如何使用字符型变量 2.2.4如何使用布尔型变量 2.2.5基本数据类型之间的类型转换 2.2.6基本数据类型和字符串之间的...
  • 5.1.4 特殊的优化方法及场景 182 5.2 常见问题 185 5.2.1 编译时间和参数化 185 5.2.2 索引化 189 5.2.3 基数和开销估算 191 5.3 故障排查 192 5.3.1 诊断 192 5.3.2 控制 198 5.4 最佳实践 208 ...
  •  在程序中优化查询而无需改动代码。  作为Oracle SQL经典著作之一,本书为SQL开发人员指明了前行的方向,赋予了他们不断开拓的动力。 作者简介  KAREN MORTON 研究人员、教育家及顾问,Fidelity信息服务公司...
  • 如果在一个类中定义了多个同名的方法,它们或不同的参数个数或不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 18、error和exception什么区别?  error 表示恢复...
  • java语言有哪些优点? 同一个.java文件中是否可以有多个main方法 一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 如何在main方法执行前输出”hello world” java程序的初始化顺序 请说出作用域...
  • 有哪些经典的优化技术(即时编译器)? 公共子表达式消除 数组边界检查消除 方法内联 逃逸分析 如果对象不会逃逸到方法或线程外,可以做什么优化? Java与C/C++的编译器对比 物理机如何处理并发问题? Java内存模型 什么是...
  • java面试宝典

    2013-02-28 16:04:01
    1、面向对象的特征有哪些方面? 8 2、作用域public,private,protected,以及不写时的区别? 8 3、String 是最基本的数据类型吗? 8 4、float 型float f=3.4是否正确? 8 5、语句float f=1.3;编译能否通过? 8 6、short ...
  • 千方百计笔试题大全

    2011-11-30 21:58:33
    1、面向对象的特征有哪些方面? 8 2、作用域public,private,protected,以及不写时的区别? 8 3、String 是最基本的数据类型吗? 8 4、float 型float f=3.4是否正确? 8 5、语句float f=1.3;编译能否通过? 8 6、short ...
  • 【JVM】JAVA编译原理和JVM原理 42 【JVM】Java内存模型 44 【JVM】jvm内存模型 45 主内存与工作内存 45 内存间交互操作 46 重排序 48 【JVM】内存泄漏 49 【JVM】java虚拟机的区域如何划分,每一个区的动能? 49 ...
  • 代码优化;架构优化;内存泄漏优化;线程优化;Bitmap优化;网络优化;懒加载优化,启动页优化;静态变量优化;电量性能优化;view控件异常销毁保存重要信息优化;去除淡黄色警告优化;使用注解替代枚举优化;glide...
  • 这一章的目的主要是让大家了解开源系统集成商都有哪些权益和责任。这一章突出介绍了MySQL的快速成长及其在开源和数据库系统市场中的重要性。此外,这一章还清晰地勾勒出了开源运动发展的脉络。  第2章对什么是...
  • 面试题9 如何使用实时编译进行代码优化 面试题10 什么是.NET中的私有程序集 面试题11 什么是.NET中的共享程序集 面试题12 如何解决因共享组件而导致的应用程序之间的冲突 面试题13 .NET程序的开发和运行基本环境是...
  • asp.net面试题

    2011-05-27 17:56:26
    11.ASP.net的身份验证方式有哪些?分别是什么原理? 答:form认证,windows集成认证等,原理不清楚. 12.进程和线程分别怎么理解? 答:进程是老子,线程是儿子,没有老子就没有儿子,一个老子可以有多个儿子.一个儿子...
  • 6.ADO.net中常用的对象有哪些?分别描述一下。 答:connection command sqladapter dataset datatable dataview等等.写不完了. 7.如何理解委托? 答:据说相当于函数指针,定义了委托就可以在不调用原方法名称的情况...
  • java面试题典 java 面试题 经典

    热门讨论 2010-06-18 13:42:36
    1. 面向对象的特征有哪些方面? 7 2. String是最基本的数据类型吗? 7 3. int 和 Integer 有什么区别? 7 4. String 和StringBuffer的区别? 8 5. 运行时异常与一般异常有何异同? 8 6. 说出ArrayList,Vector, ...
  • 本讲将介绍如何优化ASP.NET应用程序,使每一位开发者都了解ASP.NET应用程序的优化方法,写出更高效的应用程序。 跟我一起学Visual Studio 2005(11):ASP.NET Web 应用程序安全 (Level 200) 课程简介:与应用程序...
  • 本讲将介绍如何优化ASP.NET应用程序,使每一位开发者都了解ASP.NET应用程序的优化方法,写出更高效的应用程序。 跟我一起学Visual Studio 2005(11):ASP.NET Web 应用程序安全 (Level 200) 课程简介:与应用程序...
  • 本书还有一个网站,上面本书额外的第12章“查询执行”、本书的所有代码及其他工具和脚本。  本书由知识丰富的资深专家和数位具有多年产品使用经验的讲师联手打造,是一本关于sql server工作原理的权威参考指南,...

空空如也

空空如也

1 2 3
收藏数 57
精华内容 22
关键字:

编译原理代码优化方法有哪些