美文网首页小卜java
JAVA面试汇总(四)JVM(三)

JAVA面试汇总(四)JVM(三)

作者: 汤太咸啊 | 来源:发表于2022-01-20 23:31 被阅读0次
    久违的面试汇总JVM部分的第三篇,JVM部分完结,继续学习,卷起来,come on baby

    11.StackOverflow异常有没有遇到过?⼀般你猜测会在什么情况下被触发?如何指定⼀个线程的堆栈⼤⼩?⼀般你们写多少?

    (1)每当java程序启动一个新的线程时,java虚拟机会为他分配一个栈,java栈以帧为单位保持线程运行状态;当线程调用一个方法时,jvm压入一个新的栈帧到这个线程的栈中,只要这个方法还没返回,这个栈帧就存在。
    (2)StackOverflow的意思是栈内存溢出,往栈里存放的过多,导致内存溢出。出现在递归方法,参数个数过多,递归过深。方法的嵌套调用层次太多(如递归调用),随着java栈中的帧的增多,最终导致这个线程的栈中的所有栈帧的大小的总和大于-Xss设置的值,而产生StackOverflowError溢出异常。
    (3)-Xss256k 可以设置每个线程的堆栈大小,jdk1.5以后默认是1M。个人感觉不用单独配置,除非这个服务会有大量递归调用循环操作,否则不需要单独配置。

    12.内存模型以及分区,需要详细到每个区放什么。

    (1)分为方法区,虚拟机栈,本地方法栈,堆,程序计数器
    (2)方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。对于HotSpot虚拟机来说实际上这部分在以前叫做永久代。运行时常量池,也在方法区中存储,存放编译期生成的常量,运行期间的常量也可以存储器中,例如String的intern()方法产生的。
    (3)虚拟机栈,线程私有的。每个方法在执行时,会创建一个栈帧,存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。虚拟机栈中有局部变量表部分,局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。
    (4)本地方法栈,为虚拟机使用到的Native方法服务。
    (5)Java堆,Java虚拟机管理的内存中最大的一块,虚拟机启动创建的,大部分的对象实例存储在其中,也是GC操作的重点区域,许多分配的区域,新生代、老年代、Eden,Survivor之类都在其中。
    (6)程序计数器,线程私有的内存,占用空间较小,如果现成正在执行的一个Java方法,程序计数器存储的是正在执行的虚拟机字节码指令的地址;如果是native方法,这个计数器值则为空(Undefined)。唯一不会抛出OutOfMemoryError的空间。
    (7)直接内存,这个不是Java虚拟机中的内存区域。NIO可以使用Native函数库直接分配对外内存,Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,可以提高性能,因为避免了在Java堆和Native堆中来回复制数据。如果分配了jvm大量内存,如果直接内存无法分配更多的内存时,也会抛出OutOfMemoryError。

    13.做GC时,⼀个对象在内存各个Space中被移动的顺序是什么?

    (1)大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。
    (2)大对象会直接分配到老年代中。大对象是需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制。

    byte[] a = new byte[4*1024*1024];
    

    (3)虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次MinorGC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1。对象在Survivor区中每“熬过”一次Minor GC,年龄就增加1,当它的年龄增加到一定程度(默认为15),就将会被晋升到老年代中。这个阈值可以通过-XX:MaxTenuringThreshold设置。

    14.虚拟机在运行时有哪些优化策略

    (1)针对一些热点运行的代码,虚拟机在运行过程中发现热点代码后,将其编译成本地机器码。再次运行的时候运行效率更高的本地机器码。
    (2)公共子表达式消除:如果一个表达式E已经计算过了,并且从先前的计算到现在E中的所有变量的值都没有发生变化,那个E的这次出现就成为了公共子表达式。对于这样的表示式,没有必要对它再次进行计算了,直接沿用之前的结果就可以了。
    (3)数组范围检查消除:例如在某些情况下,如果重复的取某个数组内固定位置的值,例如arr[2],只要在编译优化时判断2在arr的范围内即可,编译优化出来的机器码就不在判断范围了;另外咱们写的代码都是在循环内,重复获取数组内容,那么编译优化时,只要判断循环的范围不超过数据范围,那么编译优化的代码就可以不判断范围了,直接运行即可。
    (4)方法内联:像下面的两个方法,内联在一起看的话,可以发现f方法没什么意义,因此编译优化时,直接将下面调用f(obj);代码编译过滤掉即可。

    public static void f(Object obj){
        if)(obj != null){
            System.out.println("do something");
        }
    }
    public static void test(String[] args){
        Object obj = null;
        f(obj);
    }
    

    (5)逃逸分析:基本行为就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,称为方法逃逸。甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸。栈上分配:如果确定不会出现方法逃逸的话,编译优化时候可以将其直接分配到栈上,这样当方法执行完毕,就自动在栈上消除了,避免了垃圾收集。同步消除:如果确定一个变量不会逃逸出线程,无法被其他线程访问,那这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以消除掉。标量替换:如果一个对象不会被外部访问,并且这个对象可以被拆散的话,那程序真正执行的时候将可能不创建这个对象,而改为直接创建它的若干个被这个方法使用到的成员变量来代替,这样成员变量会分配到栈上。

    15.你知道哪些或者你们线上使⽤什么GC策略?它有什么优势,适⽤于什么场景?

    (1)标记-清除算法:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。标记和清除两个过程的效率都不高;标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
    (2)复制算法:将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。直接分成两块太占用空间,IBM提出了另一种方式,分成1个Eden和2个Survivor空间,Eden和Survivor的大小比例是8∶1,当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。分配的空间小了,可能会导致某些对象由于没有空间直接分配到老年代中。复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。
    (3)标记-整理算法:标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。这样空间连续,易于管理。另外标记-整理算法主要用于老年代的回收机制,主要是由于清理次数较少,可能被清除的对象也不多。

    谢各位的阅读,谢谢您动动手指点赞,万分感谢各位。另外以下是我之前写过的文章,感兴趣的可以点进去继续阅读。

    历史文章

    JAVA面试汇总(五)数据库(一)
    JAVA面试汇总(五)数据库(二)
    JAVA面试汇总(五)数据库(三)
    JAVA面试汇总(四)JVM(一)
    JAVA面试汇总(四)JVM(二)
    JAVA面试汇总(四)JVM(三)
    JAVA面试汇总(三)集合(一)
    JAVA面试汇总(三)集合(二)
    JAVA面试汇总(三)集合(三)
    JAVA面试汇总(三)集合(四)
    JAVA面试汇总(二)多线程(一)
    JAVA面试汇总(二)多线程(二)
    JAVA面试汇总(二)多线程(三)
    JAVA面试汇总(二)多线程(四)
    JAVA面试汇总(二)多线程(五)
    JAVA面试汇总(二)多线程(六)
    JAVA面试汇总(二)多线程(七)
    JAVA面试汇总(一)Java基础知识

    相关文章

      网友评论

        本文标题:JAVA面试汇总(四)JVM(三)

        本文链接:https://www.haomeiwen.com/subject/xhwshrtx.html