内存结构

CPU不可以直接操作堆区数据,需要通过中间高速缓存区进行相关数据操作;
我们知道Android虚拟机执行的是dex指令,我们可以先使用javac指令编译class,再通过dx指令编译查看对应java方法的dex指令;
public class Person {public void run() {Person person = new Person();person.run();}
}
编译成Person.class文件后,使用dx --dex --verbose --dump-to=a.txt --dump-method=Person.run --verbose-dump Person.class dx指令编译Person.run方法,删除无用信息后,得到文件内容以及解释如下:
Person.run:()V:
regs: 0002; ins: 0001; outs: 00010000: new-instance v0, Person // 1.在高速缓存中声明一个v0;2.将Person.class加载到方法区;3.在堆区实例化一个对象person;4.v0指向堆区的person对象;0002: invoke-direct {v0}, Person.:()V // 调用构造方法初始化person对象,并将返回值赋给v00005: invoke-virtual {v0}, Person.run:()V // 调用v0执行person.run方法;0008: return-void //返回void
public class Person {Person person;public void run() {person = new Person();person.run();}
}
编译成Person.class文件后,使用dx --dex --verbose --dump-to=a.txt --dump-method=Person.run --verbose-dump Person.class dx指令编译Person.run方法,删除无用信息后,得到文件内容以及解释如下:
Person.run:()V:
regs: 0002; ins: 0001; outs: 00010000: new-instance v0, Person // 1.在高速缓存中声明一个v0;2.将Person.class加载到方法区;3.在堆区实例化一个对象person;4.v0指向堆区的person对象;0002: invoke-direct {v0}, Person.:()V // 调用构造方法初始化person对象,并将返回值赋给v00005: iput-object v0, v1, Person.person:LPerson; //将v0赋值v1,则全局变量person(v1)就指向了堆区中的实例对象;0007: iget-object v0, v1, Person.person:LPerson; //由于cpu不能直接使用堆区数据(v1),cpu将v1的值又读了一遍到v0中;0009: invoke-virtual {v0}, Person.run:()V // 调用v0执行person.run方法;000c: return-void
Q:为什么DCL单例需要使用 volatile关键字修饰?
A:当指令进行了重排,可能会出现Person.指令在
0005: iput-object v0, v1, Person.person:LPerson 0007: iget-object v0, v1, Person.person:LPerson; 指令之后的情况,就会导致没有调用构造方法就使用了person对象的情况,而从引起问题;
如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )