ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JVM面试基础

2022-06-17 20:33:45  阅读:175  来源: 互联网

标签:字节 对象 基础 面试 线程 内存 JVM volatile 变量


JVM基础面试题

1、对象在内存中的存储布局?(对象与数组的存储不同)

  • new一个普通对象,存储布局分为:markword、类型指针(class pointer)、实例数据(instance data)、对齐(padding)。
  • markword占8个字节。
  • 类型指针(new出来的是哪个类)占4个字节。
  • 实例数据(new出来对象的成员变量)没有成员变量就是占0个字节,int(4个字节),long(8个字节)、boolean(1个字节)。
  • 对齐:如果存储占的字节不能被8整除,对齐将补齐相应字节直至被8整除。

2、Object o = new Object()在内存中占用多少个字节?

markword占8个字节,类型指针占4个字节,实例数据占0个字节,一共12个字节,不能被8整除,所以对齐补上4个字节,一共16个字节。

3、对象头具体包括什么?

  • 包括8个字节的markword以及4个字节的class pointer。
  • markword又包括三大信息:1.锁信息 2.hashcode 3.GC信息。

4、对象怎么定位?

定位方法分为直接定位(直接指针)以及间接定位(句柄方式),现在的JVM基本都是采用的直接指针方式。

句柄定位的优缺点:

  • 优点:Java栈里的变量存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)的时候只会改变句柄中的实例数据指针,而变量本身不需要改变(对象移动,变量地址不用变)。
  • 缺点:增加了一次指针定位的时间开销。

直接指针的优缺点:

  • 优点:节省了一次指针定位的开销。
  • 缺点:在对象被移动的时候变量本身地址需要跟着修改。

5、对象怎么分配(栈上-线程本地-Eden-Old)

对象多少次经过安全区后进入老年代?默认的使用的PN+PO是15次,CMS是6次。

  1. 首先尝试在栈上分配,栈上分配有两个标准需要满足:①逃逸分析 ②标量替换,栈只有256个字节,所以还需要小对象,大对象之间进入老年代,然后被全栈回收(FGC)。栈上分配的对象会随着方法的结束栈帧弹出而消亡,无需GC处理。
  2. 如果不满足栈上分配也不满足大对象,优先使用线程本地分配缓冲区(Thread Local Allocation Buff)。在Eden区中,由于空间是线程共享,会导致多个线程同时去竞争Eden区中位置而降低效率。为了减少这种情况,每个线程会在Eden区中获取一块私有空间,线程上的私有小对象会优先分配到这里,避免多个线程同时竞争一个位置,提高效率。TLAB也是位于Eden区中。
  3. 线程本地分配缓冲区失败就会分配到新生代中的Eden区中
  4. 之后如果被GC清理掉,则对象消亡,如果没有清理掉,则进入S1区,再次经过一次垃圾回收,清理掉则对象消亡,未清理掉则对象年龄足够进入老年代之后全栈回收,年龄不够则进入S2区如此循环往复。

6、简单解释对象的创建过程?(半初始化)

  1. 一个Java对象的创建过程往往包括类初始化和类实例化两个阶段

  2. 简单分为三个步骤:

    实例变量初始化:new一个对象,如果对象有成员变量,先给成员变量赋初始值,如int就是0,boolean即使false,引用类型就是null(先clinit一下)。

    invoke special:调用对象构造方法设初始值

    astore_1:建立关联

7、DCL单例模式(Double Check Lock)到底需不需要volatile?

DCL是在创建一个线程安全的单例模式广泛是使用的双重检查结构。代码如下:

private static volatile INSTANCE;
private Test() {
}
public static Test getInstance() {
    //双重检查
    if (Objects.isNull(INSTANCE)) { // Double Check Lock
        synchronized (Test.class) {
            if (Objects.isNull(INSTANCE)) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new Test();
            }
        }
    }
    return INSTANCE;
}

volatile的内存语义:

  • 当写一个volatile变量时,JMM(Java内存模型)会把该线程对应的本地内存中的共享变量值立即刷新回主内中
  • 当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,直接从主内存中读取共享变量
  • 所以volatile的写内存语义是直接刷新到主内存中,读的内存语义是直接从主内存中读取

DCL单例模式(Double Check Lock)到底需不需要volatile?答案是需要的,因为CPU会出现指令重排序的现象,从上述代码可以看到,如果没有加volatile关键字的话,那么在锁内代码中,可能 第一个进来的线程发生指令重排序现象,首先执行

INSTANCE = new Test();

并且与变量进行链接,那么变量INSTANCE还未执行构造方法,并未被赋值,所以之后的线程在第一重判断中INSTANCE!=null直接返回半初始化的对象,出现并发,违背了单例模式的概念。所以在DCL模式中需要给单例对象加上volatile关键字,它的特性之一就是禁止指令重排序

8、为什么hotspot不适用C++对象来代表java对象?

因为C++对象有一个virtual table 这个是java对象所不需要也没有的。会占用内存。

9、Class对象是在堆还是在方法区?

C++对象在方法区,Java对象在堆。

标签:字节,对象,基础,面试,线程,内存,JVM,volatile,变量
来源: https://www.cnblogs.com/Beginner-liu/p/16386966.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有