• HotSpot虚拟机对象


     Hotspot虚拟机在Java堆中对象分配、布局和访问的全过程。

    对象的创建(普通Java对象,不包括数组和Class对象)

    1、当Java虚拟机遇到一个字节码new时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号的引用,并检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,必须先执行相应类加载的过程。

    2、加载检查过后,虚拟机为新生对象分配内存(把一块确定大小的内存从堆划中分出来)。

    分配内存有两种方式:

    • 指针碰撞:Java堆中内存是绝对规整的,所有使用过的内存放在一边,没使用过的在另一边,中间放一个指针作为分界点的指示器。分配内存就是指针向没使用过的一边移动与对象大小相等的一段距离。
    • 空闲列表:Java堆中内存不规整,虚拟机来维护一个列表,记录哪些内存块是可以用的,在分配时找到一个足够大的空间划分给对象实例并更新列表上的记录。

    注意:创建对象是非常频繁的行为,即使仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的。可能在给对象A分配内存时,指针还没来得及修改,对象B又同时使用了原来的指针处理。解决方案:

    • 对分配内存空间的动作进行同步处理。
    • 本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),每个线程在Java堆中预先分配一小块内存。哪个线程要分配内存,就在哪个线程的本地缓冲区中分配,只有本地缓冲区用完了,分配新的缓冲区时才需要同步锁定。

    3、内存分配完成之后,虚拟机必须将分配的内存空间(不包括对象头)都初始化为零值,如果使用了TLAB,这项工作提前至TLAB分配时顺便进行。

    保证了对象的实例字段在Java代码中可以不赋初值就直接使用,使程序能访问到这些字段的数据类型多对应的零值。

     对象的内存布局

    存储布局分为:

    1. 对象头(Header):包括用于存储对象自身的运行时数据,类型指针。
    2. 实例数据(Instance Data):对象真正存储的有效信息。
    3. 对齐填充(Padding):起到占位符作用。

    对象的访问定位

    创建对象之后为了使用对象,Java程序会通过栈上的reference数据来操作堆上的具体对象。reference是一个指向对象的引用。reference未定义访问到堆中对象的具体位置,所以对象的访问方式是由虚拟机定义的。

    访问方式主要是两类:

    • 句柄访问:Java堆划分一块内存作为句柄池,reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据与类型数据各自具体的地址信息。优点是reference存储稳定的句柄地址,对象被移动时只改变句柄中的实例数据指针,reference不需修改。
    • 直接指针访问:reference存储的是对象地址。优点是速度快。
  • 相关阅读:
    CCF201503-2数字排序
    CCF201503-1图像旋转
    leetcode 13.罗马数字转整数
    Mysql中limit的用法
    网站访问量统计案例
    ServletContext(重要)
    Servlet(自己实现的Servlet)细节
    HttpServlet
    GenericServlet
    Servlet的相关类--ServletConfig(接口)
  • 原文地址:https://www.cnblogs.com/codercql/p/13436952.html
Copyright © 2020-2023  润新知