`
IcyFenix
  • 浏览: 358275 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
文章分类
社区版块
存档分类
最新评论

RE:关于JMM模型中工作内存、主内存和几个操作的理解

阅读更多
打捞回帖、回信来发博客是个偷懒的好办法 ZZZzzz....ZZZzzz....
------------------------------------------------------------
xuhang1128 写道
1.比如上面线程1执行to方法,我觉得就是先将3赋值给a,然后a写到主内存,

上面 assign操作所说的, transfers a value from the thread's execution engine into the thread's working copy of a variable

这句话里面的 thread's execution engine和 thread's working copy of a variable分别代表什么啊,我的理解就是将3赋值给a,然后又是用store命令将 thread's working copy of a variable搞到 main memory,这时候还不完了吗,为什么后面又是 write?

2.还有上面的线程2执行的fro方法的read所说的master copy of a variable to a thread's working memory ,这里的

master copy of a variable 又是指什么呢?规范里面好像说 thread's working memory可以使寄存器,高速缓存之类的东西,之后又用load操作将main memory 将value值搞到 thread's working copy of a variable,这里的 thread's working copy of a variable是局部变量吗还是什么

  讨论前,先来看看这几个操作的含义(书上有我就不重新打一遍了,但与出版社有版权协议,不太方便粘贴复制,就给你贴图片了):



  主内存和工作内存是什么,在这段前面的2节里面有更详细的介绍,内容太多我就不全部粘贴了,反正还有2周书就应该能出来。我做个类比可能好理解一些,简单来说你可以把它们的关系理解成PC机里面的“内存”和“处理器Cache”之间的关系,所有数据在内存中都用,但是要用的时候Cache中都有一份拷贝,如果是多CPU或者多核处理器,同一份数据还可能在不同的Cache中还有拷贝,解决内存与Cache的一致性问题,硬件里有各种一致性协议。而JVM的内存模型其中一个任务也是解决main memory和working memory之间的一致性问题。

  “thread's working copy of a variable”不是局部变量,它就是工作内存中的变量拷贝副本而已,事实上在JMM中一开始就从定义了“variable”的含义,它包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,因为后者是线程私有的 ,不会被共享,自然就不存在竞争问题。

  关于为何store之后又要write的问题,从上面图片你可以看到,这2个操作是作用在不同区域上的,你把main memory和work memory看作2间房子,这2个操作就好比开门,要把物品A从房间以拿到(复制到)房间B,自然要分别进行“拿出来”和“放进去”2个操作。为什么不定义一个诸如transfer之内的操作一次过完成呢?那是因为这6个操作都是“原子的”,不可拆分,如果定义一个原子的“transfer”操作当然也可以完成任务,但原子操作的范围更大,也就意味这个操作的锁定时间更长。这与JMM规范的基本思想:既准确又宽松(见下面图片)相违背了。



xuhang1128 写道
JVM栈,操作数栈,本地栈只是抽象的概念,HotSpot VM使用的Java栈就直接融合了概念上的JVM栈与本地栈,而在被编译过的方法的栈帧里不存在操作数栈——消失了 。不要把抽象概念与具体实现混为一谈。

这是别人说的,请问上面说的编译过的方法操作数栈消失了是什么意思啊

  首先,需要弄清楚概念,你这里发生混淆了。HotSpot里面的“本地方法栈”(Native Method Stacks)和“Java虚拟机栈”(Java Virtual Machine Stacks)合二为一了。这意味着Java方法调用和本地方法(譬如JNI方法调用)使用的是同一个栈,从使用上理解,就是-Xoss参数和-Xss参数变成了同一个,因此在HotSpot里面-Xoss无效。而“操作数栈”(Operand Stack)是栈帧(Stack Frame)的一部分,栈帧说白了就是Java虚拟机栈的栈元素。它是客观存在的,不会消失。由于JVM规范的指引或者说是限制,各种Java虚拟机都是基于栈结构的,这里的栈就是操作数栈,它是指令执行的基本前提。所以在各种虚拟机中,甚至在一个虚拟机的解析和编译执行引擎中它可以有不同的存在形式,但是总谈不上“消失”的(这里有陷阱,请看撒迦的回帖)。当然,不基于栈的虚拟机,譬如Google Android的Dalvik虚拟机(基于寄存器架构)就可以没有操作数栈,当然,那也已经不是严格意义上的“JVM”了。

xuhang1128 写道
字节码指令不还有对操作数栈的操作码,不懂了哎

  “操作数栈的操作码”这个提法不妥当的。字节码指令,或者说操作码(Opcodes)不放在操作数栈上,操作数栈既然都命名为“操作数(Operand)”,那肯定是只放运算参数、中间过程结果和运算结果的啊,放个Opcodes上去有什么意思呢?
分享到:
评论
29 楼 zhanghi123 2013-07-09  
关于你文章中的java内存模型中主内存和工作内存之间的交互方式,lock和unlock我不太理解,这两步操作是由程序员通过加同步锁实现呢,还是jvm内部自己的实现呢,很疑惑,请帮忙解答一下谢谢。
28 楼 zhanghi123 2013-07-04  
关于你文章中的java内存模型中主内存和工作内存之间的交互方式,lock和unlock我不太理解,这两步操作是由程序员通过加同步锁实现呢,还是jvm内部自己的实现呢,很疑惑,请帮忙解答一下谢谢。
27 楼 zhanghi123 2013-07-04  
请教一下,关于主内存和工作内存之间的八个操作,第一步和第二部的操作,lock和unlock,我不理解,我想问一下,这个lock和unlock的操作是我们要自己要用同步写的呢,还是由jvm自己完成的呢?若是自己完成的,是如何完成的呢。
26 楼 zhanghi123 2013-07-04  
请教一下,关于主内存和工作内存之间的八个操作,第一步和第二部的操作,lock和unlock,我不理解,我想问一下,这个lock和unlock的操作是我们要自己要用同步写的呢,还是由jvm自己完成的呢?若是自己完成的,是如何完成的呢。
25 楼 jayjayjaylun 2012-05-07  
RednaxelaFX
agapple 写道
volatile也是字段可以持有的属性。getfield在具体JVM的实现里会有相应处理。


Boss门上面提到的volatile 我始终不解,IcyFenix,RednaxelaFX能否解答:

8.7 Rules for volatile Variables
If a variable is declared volatile, then additional constraints apply to the operations of each thread. Let T be a thread and let V and W be volatile variables.

1. A use operation by T on V is permitted only if the previous operation by T on V was load, and a load operation by T on V is permitted only if the next operation by T on V is use. The use operation is said to be "associated" with the read operation that corresponds to the load.

2. A store operation by T on V is permitted only if the previous operation by T on V was assign, and an assign operation by T on V is permitted only if the next operation by T on V is store. The assign operation is said to be "associated" with the write operation that corresponds to the store.

3. Let action A be a use or assign by thread T on variable V, let action F be the load or store associated with A, and let action P be the read or write of V that corresponds to F. Similarly, let action B be a use or assign by thread T on variable W, let action G be the load or store associated with B, and let action Q be the read or write of W that corresponds to G. If A precedes B, then P must precede Q. (Less formally: operations on the master copies of volatile variables on behalf of a thread are performed by the main memory in exactly the order that the thread requested.)

关于这个规则,有几个疑问:
class Foo{
   int i=1;
     say(){
     int a=i; //1. read(i)->load(i)->use(i) 
     int b=i; //2. use(i)
}

1. 在b的us操作之前[read(i)->load(i)]这2步动作是不是可选的? 这个时候用的是Thread Memory第一步缓存的那个i?
2. 而如果i是volatile的那么一定会发生这个几步动作read(i)->load(i)->use(i)?
3. 也就是说要使用volatile之前一定要从Main Memory那里去取?

class Bar{
   int valotile i=1;
   set(int var){
  i= var;   
}

public void set(int);
  Code:
   Stack=2, Locals=2, Args_size=2
   0:   aload_0
   1:   iload_1
   2:   putfield        #18; //Field i:I
   5:   return

}


4. aload_0指的是 read(var)->load(var)这2步动作?
5. aload_1指的是 read(i)->load(i)这2步动作?
6. putfield指的是 use(var)->assign(i)->store(i)->write(i)这几步动作?
  按照规范第2条use(var)->assign(i)->store(i)->write(i)这几步一定是同时发生而且一定会发生,当然use(var)->assign(i)这步中间可以有其他指令eg: use(var)-read(c)->load(c)->use(c)>assign(i)?

7.如上面的列子Thread_1.set(10) 同时 Thread_2.set(9),
  Thread_1 跟 Thread_2 分别执行的actions序列是这样磨: read(var)->load(var)->read(i)->load(i)->use(i)->use(var)->assign(i)->store(i)->write(i)?
如果是这样的话当Thread_1在执行store(i)->write(i)[写?]之前Thread_2
执行到了这一步(那到了Main Memory的旧值)
read(var)->load(var)->read(i)->load(i)->use(i)->use(var),
当Thread_1写完10,Thread_2再写9? 这跟用不用volatile不时一样吗?

当然volatile可以解决reordering的问题.

问题比较多 2位boss 给点耐心哈,最好出篇这样的文章来帮小弟扫下盲拜托了.... ^^
 

24 楼 RednaxelaFX 2011-06-09  
agapple 写道
hi 撒加 & IcyFenix ,弱弱的问几个低级的问题:

好说好说

agapple 写道
不知道blog中所提到的规范中:read/load, store/write的体现是在哪?
是不是getfield的指令实现时会拆分成read/load的两个动作

准确来说…不是。
首先你要看前面的回复。在新版规范里已经没有“read/load”“write/store”这样的描述,而改为read/volatile read,write/volatile write了。就是因为原本的描述方式不够好。

如果要深究,在原本的JMM规定下,对非volatile成员变量的读写会在JVM实现中不需要做任何特别的事情,read/load的区别单纯在现代内存层次结构上就会反映出来;
对volatile成员变量的读写则会由JVM根据平台条件(硬件/OS)做相应的同步操作。
但新版规范不再使用read/load、write/store这样的概念去描述了,所以我觉得没必要在这点上纠结。

agapple 写道
2. use/assign的理解。 类比一下操作系统的一些概念,类似于操作数寄存器。 load/store的操作只是针对局部变量区,类似于cpu cache。主内存类似于memory的访问

如果这样能方便你理解的话,那就这样想像可以。

agapple 写道
3. volitile的可见性的体现。 因为在看生成的bytecode中getfield/putfield中并没有啥特殊的处理,唯一的就是在对应的field信息中保留了volatile信息。那是不是意味着具体的可见性的处理,会体现在getfield针对不同类型的处理上。

是的,getfield/putfield、getstatic/putstatic这些字节码指令都比较有趣,它们会从字段自身的元数据获得很多信息来做相应处理。
例如说,JVM的字节码指令里许多都有类型前缀,iload只能操作int型数据之类;但getfield却可以操作任意类型数据,取决于它的参数的字段的类型是什么。所以iload保证会消耗操作数栈的一个slot,但getfield却没有保证,1个或2个slot都有可能,要看参数的字段的元数据。
volatile也是字段可以持有的属性。getfield在具体JVM的实现里会有相应处理。
23 楼 agapple 2011-06-09  
RednaxelaFX 写道
IcyFenix 写道
好的,你的回复我在正文中用红色字体标识出来了。

anyway,我还是认为,如果我们的计算机本身就是栈架构的,那就没有哪款编译器会做削除操作栈这种事情。当然,这个“如果”是个海市蜃楼、空中楼阁。

呵呵,“如果”。

这事情很简单。一个基于寄存器的虚拟架构在一个基于寄存器的实际硬件上仍然很可能会把那些虚拟寄存器分配到硬件的内存里而不是硬件的寄存器里。例子多的是。

如果有人非要在基于栈的硬件上把削除了操作数栈的方式实现出来(把原本的操作数栈转换为虚拟寄存器然后分配到内存里),那完全可行。虽然很难想像为什么要这样做。
但在基于寄存器的机器上,这操作数栈的语义想怎么实现就有许多很现实的可能性。完全按照原样实现也行,部分削除也行,完全削除也行。

其实很多东西只要自己写过就很容易理解…


hi 撒加 & IcyFenix ,弱弱的问几个低级的问题:

1. 所谓主内存中的数据,我的理解应该即是一个Object的一些属性数据(当然会有情况出现栈上分配)。
public class Volatile {
	
	public String name ;
	public volatile int id = 1;
        public static void main(String args[]) {
		Volatile v = new Volatile();
		v.name = "a";
		v.id++;
		System.out.println(v.name);
		System.out.println(v.id);
	}
}

按照这样的代码,对id属性的访问理论上满足从主内存到工作内存的交换。但bytecode中,仅仅出现getfiled/putfield的指令。
对应的指令:
   14:	aload_1
   15:	dup
   16:	getfield	#2; //Field id:I
   19:	iconst_1
   20:	iadd
   21:	putfield	#2; //Field id:I

不知道blog中所提到的规范中:read/load, store/write的体现是在哪?
是不是getfield的指令实现时会拆分成read/load的两个动作

2. use/assign的理解。 类比一下操作系统的一些概念,类似于操作数寄存器。 load/store的操作只是针对局部变量区,类似于cpu cache。主内存类似于memory的访问

3. volitile的可见性的体现。 因为在看生成的bytecode中getfield/putfield中并没有啥特殊的处理,唯一的就是在对应的field信息中保留了volatile信息。那是不是意味着具体的可见性的处理,会体现在getfield针对不同类型的处理上。

先前仔细看了JLS后,联系到具体的实现,问题比较多,望能给与解惑。
22 楼 kingquake21 2011-06-09  
RednaxelaFX 写道
kingquake21 写道
我一直认为要看的JAVA规范是JLS 3rd 和 JVMS 2nd呢,我们用的JDK1.5

JLS要看3没错。
JVMS不知道为什么在Java 5的时候没有跟着一起发布更新的整合版本,而只出了个补丁:http://java.sun.com/docs/books/jvms/second_edition/jvms-clarify.html
(留意补丁的最后一段)

如果要看的话,应该看JVMS2+补丁。

呵呵,这就是我想要的,谢谢撒迦
21 楼 RednaxelaFX 2011-06-08  
kingquake21 写道
我一直认为要看的JAVA规范是JLS 3rd 和 JVMS 2nd呢,我们用的JDK1.5

JLS要看3没错。
JVMS不知道为什么在Java 5的时候没有跟着一起发布更新的整合版本,而只出了个补丁:http://java.sun.com/docs/books/jvms/second_edition/jvms-clarify.html
(留意补丁的最后一段)

如果要看的话,应该看JVMS2+补丁。
20 楼 kingquake21 2011-06-08  
RednaxelaFX 写道
kingquake21 写道
请教一下,为什么JLS3.0里面把inter-thread的action的描述改成了下面这种方式呢?在JLS2.0中的描述还依旧可以参考吗?

你应该先阅读FAQ看看:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

JLS2的JMM描述方式太杯具了所以被废了 


这个FAQ确实很不错,以前也看过
我一直认为要看的JAVA规范是JLS 3rd 和 JVMS 2nd呢,我们用的JDK1.5
19 楼 RednaxelaFX 2011-06-08  
不知道是不是Oracle准备用自己的出版社来出JVMS3。应该年内就有机会看到的。
Oracle Press,Prentice Hall,之类的嗯
18 楼 IcyFenix 2011-06-08  
RednaxelaFX 写道
kingquake21 写道
哦,我在VM规范里面找到了,那段描述从JLS移到VMS里面了

不不不…你看的是JVMS2么?不要看那份了,那是JDK 1.2时代的。
看这个:http://jcp.org/aboutJava/communityprocess/maintenance/jsr924/index3.html


说起JVMS3,有没有小道消息这规范的正式版啥时候出来呀?

Addison-Wesley出版社回信说:
Addison-Wesley 写道

We canceled the pub plan of the 3rd edition as I checked right now.

Best,
17 楼 RednaxelaFX 2011-06-08  
kingquake21 写道
哦,我在VM规范里面找到了,那段描述从JLS移到VMS里面了

我上面给的链接是JVMS3的草案。看这段:
JMVS3, 1.3 写道
In The Java™ Virtual Machine Specification, Second Edition, Chapter 8
detailed the low-level actions that explained the interaction of Java virtual
machine threads with a shared main memory. It was adapted from Chapter 17 of
The Java™ Language Specification, First Edition.
Chapter 17 in The Java™ Language Specification, Third Edition, was updated
to incorporate The Java™ Memory Model and Thread Specification produced by
the JSR-133 Expert Group. The reader is referred to that chapter for information
about threads and locks.
16 楼 RednaxelaFX 2011-06-08  
kingquake21 写道
哦,我在VM规范里面找到了,那段描述从JLS移到VMS里面了

不不不…你看的是JVMS2么?不要看那份了,那是JDK 1.2时代的。
看这个:http://jcp.org/aboutJava/communityprocess/maintenance/jsr924/index3.html
15 楼 kingquake21 2011-06-08  
哦,我在VM规范里面找到了,那段描述从JLS移到VMS里面了
14 楼 RednaxelaFX 2011-06-08  
kingquake21 写道
请教一下,为什么JLS3.0里面把inter-thread的action的描述改成了下面这种方式呢?在JLS2.0中的描述还依旧可以参考吗?

你应该先阅读FAQ看看:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

JLS2的JMM描述方式太杯具了所以被废了 
13 楼 kingquake21 2011-06-08  
请教一下,为什么JLS3.0里面把inter-thread的action的描述改成了下面这种方式呢?在JLS2.0中的描述还依旧可以参考吗?
17.4.2   Actions
An inter-thread action is an action performed by one thread that can be
detected or directly influenced by another thread. There are several kinds of inter-
thread action that a program may perform:
• Read (normal, or non-volatile). Reading a variable.
• Write (normal, or non-volatile). Writing a variable.
• Synchronization actions, which are:
◆ Volatile read. A volatile read of a variable.
◆ Volatile write. A volatile write of a variable.
◆ Lock. Locking a monitor
◆ Unlock. Unlocking a monitor.
◆ The (synthetic) first and last action of a thread
◆ Actions that start a thread or detect that a thread has terminated, as
described in §17.4.4.
• External Actions. An external action is an action that may be observable out-
side of an execution, and has a result based on an environment external to the
execution.
• Thread divergence actions (§17.4.9). A thread divergence action is only per-
formed by a thread that is in an infinite loop in which no memory, synchroni-
zation or external  actions are performed. If a thread performs a thread
divergence action, it will be followed by an infinite number of thread diver-
gence actions.
12 楼 xuhang1128 2011-06-08  
xuhang1128 写道
IcyFenix 写道
RednaxelaFX 写道
嗯这位同学拿我的站内信回复去问你了么。


哈哈哈,我一看到站内信中“不要把抽象概念与具体实现混为一谈”这句,脑子里就冒出一个念头,这话8成是撒迦说的。

嘿嘿,感觉世界好小,谢谢两位

11 楼 xuhang1128 2011-06-08  
IcyFenix 写道
RednaxelaFX 写道
嗯这位同学拿我的站内信回复去问你了么。


哈哈哈,我一看到站内信中“不要把抽象概念与具体实现混为一谈”这句,脑子里就冒出一个念头,这话8成是撒迦说的。

嘿嘿,感觉世界好小
10 楼 RednaxelaFX 2011-06-07  
话说你的截图里有个注脚把klass pointer写成klass point了
之前没看到,糟糕 =_=|||

相关推荐

Global site tag (gtag.js) - Google Analytics