JVM的一些总结(面试须知)

1 JVM 内存分哪几个区,每个区的作用是什么?

java 虚拟机主要分为以下几个区:

  1. 方法区:
    a. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生 GC,在这里进行的 GC 主要是对方法区里的常量池和对类型的卸载
    b. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
    c. 该区域是被线程共享的。
    d. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。
  2. 虚拟机栈:
    a. 虚拟机栈也就是我们平常所称的栈内存,它为 java 方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
    b. 虚拟机栈是线程私有的,它的生命周期与线程相同。
    c. 局部变量表里存储的是基本数据类型、returnAddress 类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定
    d. 操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
    e. 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。
  3. 本地方法栈:
    本地方法栈和虚拟机栈类似,只不过本地方法栈为 Native 方法服务。
  4. 堆:
    java 堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。
  5. 程序计数器:
    内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个 java 虚拟机规范没有规定任何 OOM 情况的区域。

2 Java 类加载过程?

Java 类加载需要经历一下几个过程:

  1. 加载
    加载是类加载的第一个过程,在这个阶段,将完成以下三件事情:
    a. 通过一个类的全限定名获取该类的二进制流
    b. 将该二进制流中的静态存储结构转化为方法运行时数据结构
    c. 在内存中生成该类的 Class 对象,作为该类的数据访问入口。
  2. 验证
    验证的目的是为了确保 Class 文件的字节流中的信息不会危害到虚拟机.在该阶段主要完成以下四种验证:
    a. 文件格式验证:验证字节流是否符合 Class 文件的规范,如主次版本号是否在当前虚拟
    机范围内,常量池中的常量是否有不被支持的类型.
    b. 元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不
    被继承的类等。
    c. 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳
    转指令是否正确等。
    d. 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。
    e. 准备
    准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。
  3. 解析
    该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。
  4. 初始化
    初始化是类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的 Java 程序代码。

3 java 中垃圾收集的方法有哪些?

1 ) 引用计数法 应用于:微软的 COM/ActionScrip3/Python 等
a) 如果对象没有被引用,就会被回收,缺点:需要维护一个引用计算器
2 ) 复制算法 年轻代中使用的是 Minor GC,这种 GC 算法采用的是复制算法(Copying)
a) 效率高,缺点:需要内存容量大,比较耗内存
b) 使用在占空间比较小、刷新次数多的新生区
3 ) 标记清除 老年代一般是由标记清除或者是标记清除与标记整理的混合实现
a) 效率比较低,会产生碎片。
4 ) 标记压缩 老年代一般是由标记清除或者是标记清除与标记整理的混合实现
a) 效率低速度慢,需要移动对象,但不会产生碎片。
5 ) 标记清除压缩 标记清除-标记压缩的集合,多次 GC 后才 Compact
a) 使用于占空间大刷新次数少的养老区,是 3 4 的集合体

4 如何判断一个对象是否存活?( 或者 GC 对象的判定方法)

1.引用计数法:每个对象有一个引用计数器,被引用则加1,引用失效一次则减1,为0意味着垃圾对象,可被GC回收
2.可达性算法:该对象有无引用链接,GC Roots无法到达的对象则是垃圾回收的对象

5 什么是类加载器,类加载器有哪些?

实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。
主要有一下四种类加载器:

  1. 启动类加载器(Bootstrap ClassLoader)用来加载 java 核心类库,无法被 java 程序直接引用。
  2. 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  3. 系统类加载器(system class loader)也叫应用类加载器:它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
  4. 用户自定义类加载器,通过继承 java.lang.ClassLoader 类的方式实现。

6 简述 Java 内存分配与回收策略以及 Minor GC 和 和 Major GC(full GC)

内存分配:

  1. 栈区:栈分为 java 虚拟机栈和本地方法栈
  2. 堆区:堆被所有线程共享区域,在虚拟机启动时创建,唯一目的存放对象实例。堆区是gc 的主要区域,通常情况下分为两个区块年轻代和年老代。更细一点年轻代又分为 Eden区,主要放新创建对象,From survivor 和 To survivor 保存 gc 后幸存下的对象,默认情况下各自占比 8:1:1。
  3. 方法区:被所有线程共享区域,用于存放已被虚拟机加载的类信息,常量,静态变量等数据。被 Java 虚拟机描述为堆的一个逻辑部分。习惯是也叫它永久代(permanment generation)
  4. 程序计数器:当前线程所执行的行号指示器。通过改变计数器的值来确定下一条指令,比如循环,分支,跳转,异常处理,线程恢复等都是依赖计数器来完成。线程私有的。

回收策略以及 Minor GC 和 和 Major GC: :

  1. 对象优先在堆的 Eden 区分配。
  2. 大对象直接进入老年代。
  3. 长期存活的对象将直接进入老年代。
    当 Eden 区没有足够的空间进行分配时,虚拟机会执行一次 Minor GC.Minor GC 通常发生在新生代的Eden区,在这个区的对象生存期短,往往发生GC的频率较高,回收速度快;FullGc/Major GC 发生在老年代,一般情况下,触发老年代 GC 的时候不会触发 Minor GC,但是通过配置,可以在 Full GC 之前进行一次 Minor GC 这样可以加快老年代的回收速度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值