Class类文件结构
class文件是一组以8字节为单位的二进制流,只有两种数据类型:无符号数(基本数据类型),表(复合数据类型)
魔数
版本号
常量池(占class空间最大的数据之一,从1开始计数)
1.字面量 :接近于java层面的常量概念,如字符串,声明为final的常量
2.符号引用:类和接口的全限定名,字段和方法的描述符
字段描述符:描述字段数据类型
方法描述符:描述方法参数列表和返回值
访问标志
类索引,父类索引,接口索引集合
字段表集合(描述接口或类中声名的变量,不包括方法中的局部变量)
方法表集合
属性表集合(如,方法表,属性表都可以带有自己的属性表,如code属性存方法的代码信息)
对象的创建(非Class类)
0.准备工作,这个指令的参数是否可以在常量池中定位到一个类的符号引用,检查这个类是否已经被加载,解析初始化,如果没有,先执行相应的类加载过程
1.分配内存(堆中)
2.分配的内存空间都初始化为零值
3.init根据程序员的意愿初始化
分配内存
对象所需内存的大小在类加载完成后便完全确定(JVM可以通过普通Java对象的类元数据信息确定对象大小);
为对象分配内存相当于把一块确定大小的内存从Java堆里划分出来
1. 指针碰撞
如果Java堆是绝对规整的:一边是用过的内存,一边是空闲的内存,中间一个指针作为边界指示器;
分配内存只需向空闲那边移动指针,这种分配方式称为"指针碰撞"(Bump the Pointer);
2. 空闲列表
如果Java堆不是规整的:用过的和空闲的内存相互交错;
需要维护一个列表,记录哪些内存可用;
分配内存时查表找到一个足够大的内存,并更新列表,这种分配方式称为"空闲列表"(Free List);
Java堆是否规整由JVM采用的垃圾收集器是否带有压缩功能决定的;
所以,使用Serial、ParNew等带Compact过程的收集器时,JVM采用指针碰撞方式分配内存;而使用CMS这种基于标记-清除(Mark-Sweep)算法的收集器时,采用空闲列表方式;
对象的访问定位
1.通过句柄访问对象
好处:reference中存的是稳定的句柄地址,在GC时对象被移动只会改变实例数据指针,而reference本身不需要改变
2.通过直接指针访问对象
好处:访问速度快