java内存模型之初见


两张图分析java内存数据分配

                                                   运行时数据区
 
                                           Java堆中各代分布
PS:各代的说明:
Young:主要是用来存放新生的对象。
Old:主要存放应用程序中生命周期长的内存对象。
Permanent:是指内存的永久保存区域,主要存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域. 它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。

堆的参数说明
堆设置 -Xms :初始堆大小 -Xmx :最大堆大小 -XX:NewSize=n :设置年轻代大小 -XX:NewRatio=n: 设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 -XX:SurvivorRatio=n :年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5 -XX:MaxPermSize=n :设置持久代大小 收集器设置 -XX:+UseSerialGC :设置串行收集器 -XX:...

                             
JAVA内存模型
       仔细阅读了java官方网站提供的“The Java Language Specification”( 以下简称jls),第17.4章节的“Memory Model”,该篇文档篇幅较少,描述在某些地方比较晦涩,阅读中很不易理解,然而为求领悟透彻,竭力揣摩了文档内容,这里对所得理解做以记录。
      寻找一句话描述内存模型
      “The Java programming language memory model works by examining each read in an execution trace and checking that the write observed by that read is valid according to certain rules.”
上面这句话引自jls,个人认为这句话比较精准地描述了java的memory model所做的事情——决定程序中的每一次读都是正确的有效的值。
      内存模型作用对象
      在java内存中,instance fields(成员变量)、static fields(静态变量)以及array elements(数组的元素)这些数据是存储在堆内存(这里是广义的堆,包含了方法区),也就是说只有这一部分数据会被memory model所影响。
     三个order
Program Order
      ”Among all the inter-thread actions performed by each thread t, the program order of t is a total order that reflects the order in which these actions would be performed according to the intra-thread semantics of t.”
       Inter-thread actions是指会被其他线程影响的actions,而intra-thread actions是与之相反的,针对单个线程而言,线程隔绝的操作。
       上面这段话的意思就是说,对于一个线程来说,其inter-thread actions的执行顺序反映到单独的线程(也就是自身,先抛开其他线程不论)上的执行顺应该是符合intra-thread的情景的,这样inter-thread actions的一种执行顺序就称为program order。那么什么是intra-thread的情景呢,引用jls,“The actions of each thread in isolation must behave as governed by the semantics of that thread, with the exception that the values seen by each read are determined by the memory model.”也就是对一个线程来说,其在隔绝其他线程的情况下的actions执行顺序。
       如果一组actions,这组操作是包含很多个线程的actions,如果这些操作都是按照program order的顺序来执行的话,而且满足这个条件:
each read r of a variable v sees the value written by the write w to v such that:
• w comes before r in the execution order, and
• there is no other write w' such that w comes before w' and w' comes before r in
the execution order.
      就称为是sequentially consistent。
      sequentially consistent是一种很强大的机制来保证可见性和程序的执行顺序,但是仅仅有sequentially consistent是不够的,一些需要批量处理的操作可能无法完成。这就引出了synchronization order。
synchronization order
       synchronization order比较好理解,一句话简单说就是所有同步操作的执行顺,synchronization order必须是和program order具有一致性的,也就是一组操作按照synchronization order顺序执行也必须一定是符合program order顺序的。
Happens-Before Order
      Happens-before order根据我个人的理解是一种虚拟的执行顺序规则,它是建立在前面两种order的定义上的,也就是program order和synchronization order建立起happens-before order。
      ”A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.“
      ”If a program is correctly synchronized, then all executions of the program will appear to be sequentially consistent.“
       上面引述的这两句话说明的是,一个正确的同步(synchronization)处理顺序能够避免出现数据读写竞争的情况,也就是让程序的执行是sequentially consistent.
       同时也说明,一个正确的同步(synchronization)处理顺序也就与program order一起建立起了一个最好的happens-before order,这个happens-before order可以避免出现数据读写的竞争,因为happens-before order是建立在前两者的基础上的。
      Well-Formed Executions
      给出一个execution E = < P, A, po, so, W, V, sw, hb >。括号中各项的释义:
      • P - a program
      • A - a set of actions
      • po - program order, which for each thread t, is a total order over all actions
performed by t in A
      • so - synchronization order, which is a total order over all synchronization actions
in A
      • W - a write-seen function, which for each read r in A, gives W(r), the write action
seen by r in E.
      • V - a value-written function, which for each write w in A, gives V(w), the value
written by w in E.
      • sw - synchronizes-with, a partial order over synchronization actions
      • hb - happens-before, a partial order over actions
      Well-Formed Executions应该满足下列条件:
      1. Each read sees a write to the same variable in the execution.对每一个读操作来说,我们都有一个对应的写操作供读操作可见。
      2. The happens-before order is a partial order.
The happens-before order is given by the transitive closure of synchronizes with edges and program order. It must be a valid partial order: reflexive,transitive and antisymmetric.
      这一段表述也是在说明,happens-before order是有synchronization和program order决定的。
      3. The execution obeys intra-thread consistency.
也就是操作的总体执行顺序对应到每一个线程应该是同线程隔离时的操作顺序一致的。
      4. The execution is happens-before consistent
      A set of actions A is happens-before consistent if for all reads r in A, where W(r) is the write action seen by r, it is not the case that either hb(r, W(r)) or that there exists a write w in A such that w.v = r.v and hb(W(r), w) and hb(w, r).
       这一段话说明了什么是happens-before consistent。
       5. The execution obeys synchronization-order consistency
For all volatile reads r in A, it is not the case that either so(r, W(r)) or that there exists a write w in A such that w.v = r.v and so(W(r), w) and so(w, r).
       这一段话描述了什么是synchronization-order consistency。
       Causality Requirements(Happens-Before orders 存在的问题)
“We refer to the issue of when reads can see future writes as causality”这是一个有关causality一个不是很正式的定义。
先从一个例子说起:
 
       对于这个例子,有两种执行顺序都遵从well-formed executions的条件。
A、 sequentially consistent
       也就是上面的四个操作按照program order执行,这样是不可能会出现x=1,y=1的结果的。在这种执行情境下,不会出现读写竞争。
B、 happen-before consistent
       r1 = x; // sees write of x = 1
       y = 1;
       r2 = y; // sees write of y = 1
       x = 1;
       根据happen-before consistent的定义,在x=1和r1=x这两个操作没有存在其他happens-before操作阻止这一先写后读的操作,所以这一个操作是可以允许发生的。但这样的结果显然是不允许的。因为不存在任何一个sequentially consistent execution会带来这样的结果。这就是happens-before order所存在的一个问题,为了解决这个问题,memory model采用了一种验证方法——逐层建立一系列committed actions,直至一个well-formed Execution中所有的action都能够被正确提交(commit),这样做是力在保证所有的actions都是按照sequentially consistent的原则来执行的。
      memory model在逐层建立起committed actions的时候是有一系列约束的:
     1. Ci is a subset of Ai
     2. hbi|Ci = hb|Ci
     3. soi|Ci = so|Ci
      The values written by the writes in Ci must be the same in both Ei and E. Only the reads in Ci-1 need to see the same writes in Ei as in E. Formally:
     4. Vi|Ci = V|Ci
     5. Wi|Ci-1 = W|Ci-1
     All reads in Ei that are not in Ci-1 must see writes that happen-before them. Each read r in Ci - Ci-1 must see writes in Ci-1 in both Ei and E, but may see a different write in Ei from the one it sees in E. Formally:
     6. For any read r in Ai - Ci-1, we have hbi(Wi(r), r)
     7. For any read r in (Ci - Ci-1), we have Wi(r) in Ci-1 and W(r) in Ci-1
     Given a set of sufficient synchronizes-with edges for Ei, if there is a release-acquire pair that happens-before (§17.4.5) an action you are committing, then that pair must be present in all Ej, where j ≥ i. Formally:
     8. Let sswi be the swi edges that are also in the transitive reduction of hbi but not in po. We call sswi the sufficient synchronizes-with edges for Ei. If sswi(x, y) and hbi(y, z) and z in Ci, then swj(x, y) for all j ≥ i.
If an action y is committed, all external actions that happen-before y are alsocommitted.
     9. If y is in Ci, x is an external action and hbi(x, y), then x in Ci.
     而在上面的例子中,如果采用happens-before consistent顺序执行的话,则会因为判断条件无法看到数据读写竞争的结果而导致无法提交写操作。
     总结:memory mode在确定一个execution是否合法时,判断三个consistent——sequentially consistent、synchronization consistent以及happens-before consistent。再根据causality的校验条件对其进行校验。

附注:intra-thread actions的定义:
单线程语义是内在一致的,这要求运行时环境(虚拟机或CPU)在单线程语境下,要至少提供以下保证:
1. 对同一内存对象的交替读,写,是有序的。程序中的先读后写,或先写后读,不能被打乱。这是合乎逻辑的。
2. 依赖性的内存访问,也必须是有序的。如从内存对象A中加载地址,再依据读到的地址,读取所指向的值。不能被打乱。这也是合乎逻辑的。

只有至少保证这两点,单线程语义才能保证:the complete prediction of the behavior of a thread based on the values seen by read actions within the thread.

线程内语义(Intra-thread semantics)是对单线程语义的推广。即单线程语义,再加上:
with the exception that the values seen by each read are determined by the memory model.

猜你喜欢

转载自guoshuainh.iteye.com/blog/2216560
今日推荐