zoukankan      html  css  js  c++  java
  • java面试题目之JVM(YW制作仅供参考)

    1.JVM工作原理

    2.JVM组成部分及其作用。

    java虚拟机分为两个子系统和两个组件。

    两个子系统分别是类加载器和执行引擎,类加载器负责加载字节码(.class)文件到JVM的内存中,执行引擎负责执行classes下面的指令,还可以修改程序计数器的值。

    两个组件分别是运行时数据区和本地方法接口。

    运行时数据区也就是JVM的内存,本地方法接口就是和其他语言交互的接口。

    3.java应用程序运行的步骤。

    首先通过IDE集成环境编写java代码,其次通过编译器将java文件编译成字节码文件,然后通过类加载器将.class文件加载到JVM内存中。(运行字节码是由解析器完成)。

    4.类加载的过程。

    类加载分三步。加载-连接-初始化

    ①加载。类加载器将.class文件加载到JVM内存中。

    ②连接。校验:判断.class文件的安全性和正确性。

        准备:为静态变量赋值,这个值是默认值。(为静态变量分配内存空间),如果有final修饰的变量,则赋原值。

        解析:把符号引用转换为直接引用。

    ③初始化。执行静态代码块,为静态变量赋值,这个值是原值。

    5.JVM的类加载器。

    作用:负责加载字节码文件到JVM'的内存中。

    从父类加载器到子类加载器一共分为4种。分别是启动类加载器(加载核心类),扩展类加载器(加载扩展的jar),应用程序类加载器(加载classpath下面指定的内容),自定义类加载器(加载自定义的jar)。

    6.双亲委派机制

    为了能够让类加载器按需加载,避免重复加载,所以引入了双亲委派机制。

    这个机制说白了就是一个类加载器的层次模型,一个类加载器收到了一个加载类的请求,首先他不会自己尝试去加载这个类,而是由父类加载器去加载,所以每个加载的请求都会传送到根类加载器,只有当父类反馈无法加载这个类之后,子类加载器才会尝试去加载。

    使用双亲委派机制就是避免多份同样的字节码文件的加载,通过一层一层向上,看看哪一个类加载器曾经加载过这个字节码文件。

    7.forname和classload的区别。

    二者都是类加载的一种显示方式,forname得到的class是已经初始化的,而classload得到的class是没有进行连接的。

    判断:写一个类,然后在这个类中写一段静态代码块,如果使用forname发现静态代码块被执行,使用classload发现静态代码没有被执行。

    8.JVM内存模型

    jvm内存模型也就是运行时数据区。

    它分为方法区(元空间java8以后),java虚拟机栈,堆,程序计数器,本地方法栈。

    程序计数器(线程独有):它是一块较小的内存空间,他表示字节码执行的行数,通过改变程序计数器的值来判断要执行哪一条指令,程序之间的跳转就是通过程序计数器实现的,他属于逻辑计数器。

    java虚拟机栈(线程独有):是java方法执行的模型,每一次方法执行时都会创建一个栈帧,栈帧里面存放了本地变量表,操作数栈,动态链接,方法返回值。本地变量表存放本地变量,操作数栈错放临时变量值。

    本地方法栈(线程独有):和java虚拟机栈类似,不过就是java虚拟机栈服务的对象是java方法,而本地方法栈为native方法服务。

    方法区(线程共享)(元空间):存放一些编译器编译过后的一些代码等数据。

    堆(线程共享):存放一些实例(对象),也是垃圾收集管理的区域。java堆分为年轻代和老年代。

    9.JVM分代怎么工作的

    jvm分为年轻代和老年代,年轻代又分为一个Eden区和两个survivor(from和to),默认比例8:1:1,。首先对象是放在Eden区和from区的,当发生GC,Eden区存活的对象就会被放到to区,然后from区的对象就会根据年龄判断去to区还是去老年代,默认年龄15。此时Eden和from为空,然后to区和from区交换。

    10.java堆和栈的区别

    从内存空间看:栈小于堆

    从管理上看:栈自动释放,堆需要GC

    从线程看:堆是线程共享的,栈是线程独有的

    从分配上看:堆是动态分配,栈是静态和动态分配

    从效率上看:栈大于堆

    11.如何判断垃圾可以被回收

    判断垃圾是否应该回收有两种方法:程序计数法,可达性分析法。

    程序计数法:通过判断对象引用的次数来判断是否被回收,每个对象都会有一个引用计数器,被引用时应用技术器+1,引用完成时引用计数器-1,引用计数器为0时,就说明此对象可以视为垃圾。这种方式有一个弊端,就是假设父对象引用子对象,子对象反过来引用父对象,这样引用计数器的值永远不可能为0,会导致内存泄漏。

    可达性分析法:通过判断对象的引用链来判断对象是否为垃圾。从GCroot开始寻找引用节点,然后继续寻找这个节点的引用节点,当所有引用节点寻找完毕,则剩下的节点就是没有被引用的,就可以视为垃圾。

    12.什么可以被视为GC root。

    java虚拟机栈中引用的对象(栈帧的本地变量表)

    方法区中静态变量引用的对象

    方法区中常量引用的对象

    本地方法中native引用的对象

    13.垃圾回收算法

    标记-清除算法:在堆中从根节点进行扫描,对存活的对象进行标记,对堆从头到尾进行遍历,然后清除不可达的对象。这种算法会产生大量的垃圾碎片,不利于以后大对象的储存。

    复制算法:刚开始把堆分为一个对象面和一个空闲面,首先在对象面进行对象分配,当对象面满了,就会将对象面存活的对象复制到空闲面,这样对象面就变成了空闲面,空闲面就变成了对象面。然后程序就在空闲面进行对象分配。

    标记-整理算法:在堆中从根节点进行扫描,对存活的对象进行遍历,然后通过地址将存活的对象依次排序,将末节点地址以后全部清除。

    分代收集算法:新生代(存活率低):复制算法

           老年代(存活率高):标记-清除算法和标记-整理算法

    14.Minor GC 和 Full GC,触发Full GC的条件

    Minor GC发生在年轻代,首先对象分配在伊甸园区,如果伊甸园区放不下了,也有可能直接放到survivor区。

    Full GC发生在老年代。

    条件:老年代空间不足:因为标记-清除算法会产生垃圾碎片,会导致老年代空间不足,就会触发Full GC

       永久代空间不足

       CMS时出现有对象进入老年代导致老年代空间不足

       调用System.gc()

    15.垃圾收集器

    年轻代:Serial垃圾收集器(单线程)  ParNew垃圾收集器(多线程)  Parallel Scavenge垃圾收集器(多线程可控制吞吐量)

    老年代:Serial Old垃圾收集器(单线程)  Parallel Old垃圾收集器(多线程可控制吞吐量)  CMS垃圾收集器(标记-清除算法实现)

    整堆回收器:G1

    CMS:

    16.JVM调优

    工具:jconsole:对JVM线程  类等进行监控

       jvisualvm:JDK自带分析工具,分析:内存快照,程序死锁,监控内存变化,GC变化

    参数:-Xms2g:初始化堆大小为2g

       -Xmx2g:堆最大为2g

       -xx:NewRatio=4:年轻代:老年代=4:1

       -xx:survivorRatio=8   Eden:survivor=8:2

    .......

    17.软引用和弱引用

    软引用:一般维护一些可有可无的对象,内存足够的时候,软引用对象不会被回收,只有当内存不足的时候软引用对象才会被回收,如果回收之后内存依然不足,才会抛出内存溢出异常。

    弱引用:更加无用,无论内存是否够用,弱引用对象都会被回收。

  • 相关阅读:
    JAVA 之 JSTL
    IDEA 之 ERROR:无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[http://java.sun.com/jsp/jstl/core]
    JAVA 之 EL表达式
    IDEA 之 ERROR:端口被占用
    【ubuntu】windows+ubuntu 设置windows为第一启动项
    【ubuntu】Error: environment block too small. Press any key to continue
    Navicat premium15安装破解教程
    通过django中间件和python魔法方法实现自定义session(通过文件存储session)
    每日作业 7/2
    每日作业 7/1
  • 原文地址:https://www.cnblogs.com/ITYW/p/13298364.html
Copyright © 2011-2022 走看看