LoadLoad屏障:
对于这样的语句Load1; LoadLoad; Load2,
在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:
对于这样的语句Store1; StoreStore; Store2,
在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:
对于这样的语句Load1; LoadStore; Store2,
在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障:
对于这样的语句Store1; StoreLoad; Load2,
在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。
众所周知,volatile是保证可见和有序的,但不保证同步.
synchronized会保证同步性,附带着保证可见和有序
字节码层面
ACC_SYNCHRONIZED
monitorenter monitorexit
JVM层面
C C++ 调用了操作系统提供的同步机制
OS和硬件层面
X86 : lock cmpxchg / xxx
参考 https://blog.csdn.net/21aspnet/article/details/88571740
这个知道了硬件(CPU和主存)的内存模型,这里就很容易理解了,基本一样.
不管如何重排序,单线程执行结果不会改变
https://www.zhihu.com/question/52116998/answer/133400077
https://blog.csdn.net/zhaocuit/article/details/100208879
对象的大小跟虚拟机的实现和设置都有关系
普通对象和数组对象也有不同
这里可以做个实验验证下,自己写个javaagent,java.lang.instrument.Instrumentation.getObjectSize(Object o)
在终端输入下面命令,其实就是查看Java版本的命令,只不过我们指定了参数,打印出JVM的参数
java -XX:+PrintCommandLineFlags -version
得到下面的结果:
我们比较关心 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops,这俩是默认就有的;
如果想关闭,就把加号改成减号,如-XX:-UseCompressedOops
C:\windows\system32>java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=267595520 -XX:MaxHeapSize=4281528320 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version “1.8.0_112”
Java™ SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot™ 64-Bit Server VM (build 25.112-b15, mixed mode)
分为三块:对象头(Header),实例数据(Instance)和对齐填充(Padding)
对象头包括两部分
实例数据
引用类型: -XX:+UseCompressedOops 为4字节 不开启为8字节
Oops: Ordinary Object Pointers
基础类型: byte 1字节, short 2字节, int 4字节, long 8, float 4, double 8,boolean 1, char 2,
String属于引用类型
对齐填充:对齐成8的倍数,64位的机器读起来效率高一些(一个字节8位,8个字节64位)
答案是16字节
首先对象头8个字节,如果-XX:+UseCompressedClassPointers,那么ClassPointer 4个字节,然后Padding对齐,结果是16字节
如果-XX:-UseCompressedClassPointers,那么ClassPointer 8个字节,结果还是16字节
这个很复杂,要看HotSpot的源码,暂时没必要挖太深
很重要的两个东西:
锁标志位和GC标记
严格来说,有3bit表示锁的状态
对象处于不同的状态时,markword各个bit表示出不同的内容(复用存储空间)
网上找的一个说明markword的图(32位JVM的)
可以看到分代年龄占用4bit,这也是为什么,GC年龄最大为15
IdentityHashCode的问题:
当一个对象计算过identityHashCode之后,不能进入偏向锁状态
https://cloud.tencent.com/developer/article/1480590
https://cloud.tencent.com/developer/article/1484167
https://cloud.tencent.com/developer/article/1485795
https://cloud.tencent.com/developer/article/1482500
T o = new T(),这个o是怎么找到对应的对象的?
https://blog.csdn.net/clover_lily/article/details/80095580
Hotspot使用直接指针的方式
句柄池方式对GC(三色算法)友好一些
这里粗略了解下,后面讲GC时详细讲.
先尝试往栈上分配,栈弹出时回收对象;
栈上放不下的话,
如果对象很大(阈值),那就直接分配到堆内存(老年代);
如果对象不是特别大,就分配到线程本地,如果线程本地分配不下,就找新生代的Eden区