1.总体概述(多线程)
jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中(不包括局部变量和方法参数,因为它们是完全私有的),对于所有线程都是共享的。
每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
volatile变量依然有工作内存的拷贝,但是由于它特殊的操作顺序规定,每次使用之前都要先刷新,它还能禁止指令重排序优化,所以它看起来如同直接在主内存中读写访问一般。顺便一提,非原子操作,导致volatile变量的运算在并发下一样是不安全的。
Java虚拟机的即时编译器有指令重排序优化的功能,所以可能对输入代码进行乱序执行优化,CPU也会采用允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理的技术。比方Core乱序执行引擎说程序某一段有7条指令,此时CPU将根据各单元电路的空闲状态和各指令能否提前执行的具体情况分析后,将能提前执行的指令立即发送给相应电路执行。所以,缓存一致性的顺序性不能通过代码的先后顺序来保证!
2.主存模型(GC)
堆上的内存分为老年代和新生带(eden)。
在任何一个应用程序堆中,一些对象在创建后很快就成为垃圾,另一些则在程序的整个运行期间一直保持生存。经验分析表明,对于大多数面向对象的语言,包括 Java 语言,绝大多数对象――可以多达 98%(这取决于您对年轻对象的衡量标准)是在年轻的时候死亡的。当大多数对象在年轻时死亡时,复制收集器可以执行得相当好,因为复制收集器完全不访问死亡的对象,它们只是将活的对象复制到另一个堆区域中,然后一次性收回所有的剩余空间。
那些经历过第一次垃圾收集后仍能生存的对象,很大部分会成为长寿的或者永久的对象。标记-整理收集器对于长寿对象可以工作得很好,因为长寿对象趋向于沉在堆的底部,从而不用再复制。不过,标记-清除和标记-理整收集器要做很多额外的分析死亡对象的工作,因为在清除阶段它们必须分析堆中的每一个对象。