jvm系列文章之jvm内存分配机制
1.java 类在实例化过程中会大体上经历如下过程:
字节码执行引擎会在类加载器中查找A类是否已经加载,如果未加载会进行类加载过程,加载后会为该对象在堆或栈上分配内存,存在并发下的CAS和TLAB进行分配,正常情况下对象内存占用主要有三部分组成,对象头,实例数据,对象填充,其中对象头主要分为markword标记字段,jvm会根据实际的物理机操作位数(32位和64位)决定要分配给该字段的空间大小,32位机器默认为4bit,64位机器为8bit,对象头包含的内容有运行时数据hash值,gc分代年龄,锁状态,线程id,线程持有锁,偏向时间戳等信息,同时包含类型指针来指向方法区的类信息,如果是数组类型的对象,还会包含数组长度,默认4个字节,对象填充是为实例数据分配的内存占用不足4位或8位时填充使其占满4位或8位,方便和提高操作系统存取,这中间如果是64位操作系统的物理机,jvm又存在指针压缩的概念,即如果数据的物理地址超过32位小雨35位时,jvm会对改数据通过一定的压缩算法压缩成32位的数据,但是当执行到该指针时,jvm会对其进行解压,让cpu去真实的物理内存中去寻找数据,分配完内存后jvm会对类的信息执行初始化,为实例数据分配默认的值并执行构造函数,接着进行对象头的设置,最后执行init方法完成实例化,并为变量实际赋值
2.关于对象分配内存到底在哪里的问题:
一般情况下,对象是在堆上分配内存的,除非该对象未逃逸即未被调用者引用,这时候如果该对象所占用的空间,栈能为其分配内存,jvm就会将该对象在栈上创建,即该对象随着栈帧的销毁而销毁,但如果该对象栈不能为其分配足够的内存,对象的创建过程就会被放在堆内存的eden区,若eden区仍然无法提供足够的内存供该对象使用,该对象就可能被直接放到老年代。
3.关于垃圾回收算法,主要有两种,第一种叫引用计数器,即每次对象创建后,若有句柄指向该对象,则对象的引用次数+1,等到程序结束时,由于程序的局部变量总是随着方法的创建而在栈上分配内存来引用对象,方法的销毁而释放掉栈上的引用,当对象未被引用时,该对象的引用计数器置0,于是便可以进行回收,但是当引用存在循环引用时,就会导致引用计数器无法置零,所以我们jvm一般使用第二种可达性分析算法,即从main方法开始,会有一个gcroot对象,它就像一棵树,每出现一次该对象的引用,对象就会在这棵树上多出一个引用,后期一旦这棵树与gcroot根节点断开,就说明该对象已经可以当做垃圾对象,可以一次性回收。