对象

这块内容面试官一般会问,面试的难易程度也不一样,有些面试官或许让你讲讲虚拟机的内存模型即可,

有些也会让你解释垃圾回收的实现,当然也会有虚拟机调优的实战经验,线上问题排查等等。

场景对话:面试官:你对java的对象熟悉吗?

我:(对象?他应该会问一些关于对象初始化以及回收的东西吧)  嗯,略微了解(俗话说凡事不能说太满,容易被打脸)

面试官:你知道怎么创建一个对象吗?

我:1 new  2利用反射建立 3使用clone()方法 4反序列化  

面试官:你能简单说说对象的创立过程吗?

我:[检测类是否被加载]虚拟机遇到创建对象的指令时,先去检查这个指令的参数能否在常量池中定位到一个类的符号引用,并检查这个符号代表的类是否完成了类加载的过程,若无必须先执行对应的类加载。

[为对象分配内存]在类加载检查通过后,虚拟机就开始为对象分配内存,此时所需内存的大小就已经确定了。只需要在堆上分配所需要的内存即可。

[对非配的内存空间初始化零值]对象的内存分配完成后,还需要将对象的内存空间都初始化为零值,这样能保证对象即使没有赋初值,也可以直接使用。

[设置对象头信息]分配完内存空间,初始化零值之后,虚拟机还需要对对象进行其他必要的设置,设置的地方都在对象头中,包括这个对象所属的类,类的元数据信息,对象的hashcode,GC分代年龄等信息。

[执行init方法]执行完上面的步骤之后,在虚拟机里这个对象就算创建成功了,但是对于Java程序来说还需要执行init方法才算真正的创建完成,因为这个时候对象只是被初始化零值了,还没有真正的去根据程序中的代码分配初始值,调用了init方法之后,这个对象才真正能使用。

面试官:分配内存的方法你能具体说一下吗?

我:分配方法分为两种情况吧。 

   当堆中内存是绝对规整时,采用“指针碰撞”的方法,所有用过的内存放在一边,空闲的内存放在另一边,中间放一个指针作为分界点的指示器,将对象放在空闲内存区,然后指针移动相应的位置。

   当堆中内存不规整时,这时候虚拟机需要维护一个列表,来记录哪些内存是可用的。分配内存的时候需要找到一个可用的内存空间,然后在列表上记录下已被分配,这种方式成为空闲列表。

面试官:你知道对象的创建是非常频繁的,并发情况下怎么解决线程安全的呢?

我:(emmm.....这个以前看过啊,太久远了%……&努力回想)哦,对了。 

对于指针碰撞虚拟机是采用CAS来保证操作的原子性的。 第二种是在堆中为每一个线程分配一个[本地线程分配缓冲](Thread Local Allocation Buffer TLAB),哪个线程要分配空间就在哪个TLAB上分配。

只有TLAB内存用完并分配新的TLAB时才需要同步锁定,可以通过-XX+/UseTLAB参数来设置是否使TLAB 

面试官:了解得蛮详细的,你刚才说设置对象的头部信息,都包含些什么信息呢? 

我:(沃日,这有完没完....)HotSpot虚拟机的对象布局为对象头,实例数据,对齐填充(顺便把内存布局说了一下)。对象头包括:[Mark Word]存储对象的运行数据包括哈希码,GC分代年龄,锁状态标志等。另一部分存储指向方法区对象类型的指针,如果是数组对象的话,还有额外一部分用于存储数组长度。

面试官:你应该知道java程序是通过站上面的对象引用来操作堆上面具体的对象的,那引用是如何通过访问定位到对象的呢? 

我:现在比较主流的方法是使用句柄和直接指针的方式,如下:

 

HotSpot是采用的第二种直接指针的方式。

比较这两种方式的话,他们的优点: 第一种:在垃圾回收过程中对象移动是非常普遍的,栈中存储的引用可以不变,只需要改变句柄中的指针。第二种速度快并且节省空间。

面试官:okok,你了解GC么?

我:(暂时先写到这里,先去打游戏了,今晚是战斗之夜....)

 

posted @ 2017-09-09 18:32  WegYcx  阅读(198)  评论(0编辑  收藏  举报