如何做好网站优化百度搜索关键词设置
讨论的都是普通对象不包括数组和class对象
对象的创建:
类加载检查:java虚拟机遇到一条字节码new指令时,先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载、解析和初始化过,如果没有就必须先执行相应的类加载过程
分配内存:对象所需的内存的大小在类加载完成后就可以完全确定
根据堆中内存使用是否规整,分配方式可以分为“指针碰撞”和“空闲列表”两种
指针碰撞:堆中内存是规整的,用过的放在一边,空闲的另一边,中间一个指针作为分界指示器,分配内存就是把这个指针向空闲的方向挪
空闲列表:内存不规整的话就必须维护一个列表,分配的时候找到一块足够的内存分配
使用什么分配方式取决于分配方式,分配方式又取决于采用的垃圾收集器是否带有空间压缩整理的能力
多个线程都要创建的话要保证并发安全,一种方式是同步处理(使用CAS),另一种就是使用TLAB,每个线程预先在java堆里分配一小块内存
初始化零值:内存分配完成之后,虚拟机必须将分配的内存空间(不包括对象头)都初始化为零值,保证对象的实例字段在java代码中可以不赋初始值就直接使用
对象头设置:例如这个对象是哪个类的实例、如何找到类的元数据信息、哈希码、对象年龄等
到这为止,从虚拟机的角度来看,一个新的对象已经产生了;但是从java程序来看,对象创建才刚刚开始,构造函数还没开始执行,也就是class文件中的<init>()方法,一般来说new指令之后会紧接着执行<init>()方法
对象内存布局:
对象在堆中可以划分为三个部分:对象头、实例数据、对齐填充
对象头:
Mark Word:存储对象自身的运行时数据,如哈希码、GC年龄、锁状态标志等。多少位虚拟机这个部分就有多少比特
Klass Word:类型指针,指向它的类型元数据的指针。(不是所有的虚拟机实现都必须在对象数据上保留类型指针)
此外如果是java数组的话,对象头还有一块用于记录数组长度的数据
//HotSpot虚拟机的注释字段,描述32位虚拟机中Mark Word的存储布局
//Bit-format of an object header (most significant first, big endian layout below):
//
// 32 bits://32位虚拟机
// --------
// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)//没有加锁的时候
// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)//偏向锁
// size:32 ------------------------------------------>| (CMS free block)//CMS空闲块
// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)//CMS提升对象,CMS GC 中从年轻代提升到老年代的对象的特殊格式biased_lock:是否启用偏向锁,0不启用
lock:锁标志,01无锁或偏向锁(这种情况看biased_lock)、00轻量级锁、10重量级锁、11GC标记
JavaThread*:偏向锁的目标线程ID
epoch:偏向锁的时间戳,用来判断是否需要撤销偏向。epoch 是偏向锁的一个版本号,JVM 在某些情况下会批量重置偏向锁,这时就会更新 epoch
对象的访问定位:
java程序会通过栈上的reference来操作对上的具体对象,reference类型在java虚拟机规范里面只规定是一个指向对象的引用,但是没有定位这个引用应用通过什么方式去定位堆中的对象
句柄:java堆中可能会划分出一块内存作为句柄池,reference中存储的就是对象的句柄地址。句柄中包含对象实例数据和类型数据各自的地址
好处就是对象移动的话,只会改变句柄中的实例数据指针,不需要改变reference
直接指针:reference直接存储对象地址,必须考虑如何放置访问类型数据
好处是减少一次指针定位的时间开销