背景
最近在学习JAVA对象布局的一些底层实现原理,在这边做了总结归纳,方便大家学习。
CAS的最终实现(指令)
代码语言:javascript复制// cmpxchg = cas修改变量值
lock cmpxchg
JOL(java object layout) Java对象布局
常见对象内存布局:
Object、Integer、boolean(16 bytes)
String、Long、Double(24 bytes)
整型:
其中byte、short、int、long都是表示整数的,只不过他们的取值范围不一样
可以看到byte和short的取值范围比较小,而long的取值范围太大,占用的空间多,基本上int可以满足我们的日常的计算了,而且int也是使用的最多的整型类型了。
在通常情况下,如果JAVA中出现了一个整数数字比如35,那么这个数字就是int型的,如果我们希望它是byte型的,可以在数据后加上大写的 B:35B,表示它是byte型的。
同样的35S表示short型,35L表示long型的,表示int我们可以什么都不用加,但是如果要表示long型的,就一定要在数据后面加“L”。
浮点型:
- float和double是表示浮点型的数据类型,他们之间的区别在于他们的精确度不同
- float 3.402823e 38 ~ 1.401298e-45(e 38表示是乘以10的38次方,同样,e-45表示乘以10的负45次方)占用4个字节
- double 1.797693e 308~ 4.9000000e-324 占用8个字节
double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的,如果要表示一个数据是float型的,可以在数据后面加上“F”。
浮点型的数据是不能完全精确的,所以有的时候在计算的时候可能会在小数点最后几位出现浮动,这是正常的。
boolean型(布尔型):
这个类型只有两个值,true和false(真和非真)
- boolean t = true;
- boolean f = false;
char型(文本型) :
用于存放字符的数据类型,占用2个字节,采用unicode编码,它的前128字节编码与ASCII兼容
字符的存储范围在u0000~uFFFF,在定义字符型的数据时候要注意加’ ',比如 '1’表示字符’1’而不是数值1,
char c = ’ 1 ';
我们试着输出c看看,System.out.println©;结果就是1,而如果我们这样输出呢System.out.println(c 0);
结果却变成了49。
对象内存布局
对象包含三个部分,对象头、实例数据、对齐填充数据。
对齐填充字节是为了满足Java对象大小必须满足是8字节的倍数这一条件设计的,为了对象而填充一些无用字节实例数据就是在初始化数据时设定的属性和状态的内容。
对象头,存放了一些对象本身的运行时信息包含两部分 : Mark Word , Class Pointer,相较于实例数据,对象头属于一些额外的存储开销,所以它被设计得极小来提高效率。Class Pointer就是一个指针,指向了当前对象类型所在方法区中的类型数据,Mark Word存储了很多和当前对象运行时状态有关的数据。
查看对象内存布局
pom中引用依赖:
代码语言:javascript复制<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
demo:
代码语言:javascript复制public class TestClassLayout {
/**
* 打印对象内存布局
*/
@Test
public void test1() {
// Object o = new Object();
// Long o = 0L;
// Double o = 0D;
String o = "0";
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
输出结果:
代码语言:javascript复制java.lang.String object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998)
12 4 char[] String.value [0]
16 4 int String.hash 0
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal 4 bytes external = 4 bytes total
锁的信息
锁的信息是放在在对象的markword中,我们可以看下具体示例代码:
代码语言:javascript复制public class TestClassLayout {
/**
* 打印对象内存布局
*/
@Test
public void test1() {
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o) {
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
}
输出结果:
代码语言:javascript复制java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal 4 bytes external = 4 bytes total
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 20 eb 96 08 (00100000 11101011 10010110 00001000) (144108320)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal 4 bytes external = 4 bytes total
Process finished with exit code 0