JVM 知识点整理--面试必备

JVM 知识点整理

java 内存区域

1.1说一下jvm的主要组成部分及其作用?

在这里插入图片描述

JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine (执行引擎); 两个组件为Runtime data area (运行时数据区)、Native interface(本地接口) Class

  1. loader(类装载):根据给定的全限定名类名(java.lang.Object)来装载class文件到Runtime data
    area 中的method area(方法区)
  2. Execution engine(执行引擎):执行classes文件中的指令
  3. Native INterface(本地接口):与native libraries交互,是其他编程语言交互的接口、
  4. Runtime data area(运行时数据区域):这就是我们常说的JVM的内存

作用:首先通过编译器把Java代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中 ,将其放在运行时数据区的方法区内,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层的操作系统区执行,因此需要特定的命令解析器执行引擎(Execution engine),将字节码翻译成底层系统指令集,再交由CPU去执行,而这个过程中需要调用其他语言的本地库接口来实现整个程序的功能

下面是java程序运行机制详细说明
Java程序运行机制步骤

  • 首先利用IDE集成开发工具编写Java源代码,源文件的后缀为.java;
  • 再利用编译器(javac 命令)将源文件编译成字节码文件,字节码文件的后缀为 .class
  • 运行字节码文件的工作是由解释器(java命令)来完成的

在这里插入图片描述

从上图看出,Java文件通过编译器变成了.class文件,接下来类加载器又将这些.class文件加载到jvm中。
其实可以用一句话来解释:类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个Java.lang.CLass对象,用来封装在方法区内的数据结构、、

1.2说一下jvm运行时数据区

Java虚拟机在执行Java程序的过程中会把他所管理的内存区域划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有些区域随着虚拟机进程的启动而存在,有些区域则是依赖线程的启动和结束而建立和销毁
Java虚拟机所管理的内存被划为如下几个区域:
在这里插入图片描述

不同的虚拟机的运行时数据区可能略微有所不同,但都会遵从Java虚拟机规范,Java虚拟机规范规定的区域分为以下5个部分

  • 程序计数器(program counter register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成
  • Java虚拟机栈(Java Virual Machine Stacks):用于存储局部变量表,操作数栈,动态链接,方法出口等信息
  • 本地方法栈(Native Method
    Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务Java方法的,而本地方法栈是虚拟机调用Native 方法服务的
  • Java堆(Java Heap):Java虚拟机中内存最大的一块,是被线程所共享的几乎所有的对象实例都在这里分配内存
  • 方法区(method area):用于存储已被虚拟机加载的类信息,常量、静态变量,即时编译后的代码等数据

1.3 深拷贝和浅拷贝

浅拷贝(shallowcOPY) 只是增加了一个指针指向已存在的内存地址
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存
使用深拷贝的情况下,释放内存的时候不会因为浅拷贝是释放同一个内存错误

浅复制:仅仅是指向被复制内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变
深复制:在计算机中开辟一块新的内存地址用于存放复制的对象

1.4说一下堆栈的区别

物理地址
堆的物理地址分配对象是不连续的。因此性能有些慢。在GC的时候也要考虑到不连续的分配,所以有各种算法。比如,标记-清除,复制,标记-整理,分代(即新生代使用复制算法,老年代使用标记–整理算法)
栈使用的是数据结构中的栈,先进先出的原则,物理地址分配是连续的。所以性能快。
内存分别
堆因为是不连续的,所以分配的内存是在运行期确认的。因此大小不固定。一般堆大小远远大于栈。
栈是连续的,所以分配的内存大小要在编译器确认,大小是固定的

存放的内容
堆存放的是对象的实例和数组。因此该区更关注的是数据的存储
栈存放;局部变量,操作数栈,返回结果。该区更关注的是程序方法的执行
PS:
1.静态变量放在方法区
2.静态的对象方式放在堆
程序的可见度
堆对于整个的应用程序都是共享、可见的
栈只对线程可见。所以也是线程私有的。他的生命周期和线程相同

1.5队列和栈是什么?有什么区别?

队列和栈都是被用来预存储数据的。

  • 操作的名称不同。队列的插入称为入队,队列的删除称为出队。栈的插入称为进栈,栈的删除称为出栈
  • 操作的方式不同。队列是在队尾入队,队头出队,即两边都可操作。而栈的进栈和出栈都是在栈顶进行的,无法对栈底直接进行操作
  • 操作的方法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(不能从中间插入),每次离开的成员总是在队列头上了(不允许中途离队)

而栈为后进先出(LIFO).即每次删除(出栈)的总是当前栈中最新的元素,即最后插入(进栈)的元素,而最先插入的被放在栈的底部,要到最后才能删除

1.6Java会存在内存泄露吗?请简述

内存泄漏是指不再被使用的对象或者变量一直被占据在内存中。理论上来说,Java是有GC垃圾回收机制的,也就是说,不再被使用的对象会被GC自动回收掉,自动从内存中清除。
但是,即使这样,Java也还是存在着内存泄露的情况,Java导致内存泄露的原因很明确;长生命周期的对象持有着短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有着他的引用而导致不能被收回,这就是Java中内存泄露发生的场景。

1.7说-下JVM有哪些垃圾回收器

如果说垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。下图展示了7种作 用于不同分代的收集器,其中用于回收新生代的收集器包括Serial、ParNew、Parallel Scavenge,回收老年代的收集器包括Serial Old Parallel Old、CMS,还有用于回收整个Java堆的G1收集器。不同收集器之间的连线表示它们可以搭配使用。

  1. Serial 收集器(复制算法):新生代单线程收集器,标记和清理都是单线程,优点是简单高效
  2. ParNew
    收集器(复制算法):新生代并行收集器,实际上是serial收集器得多线程版本,在多核CPU环境下有着比serial更好的表现
  3. Parallel Scavenge
    收集器(复制算法):新生代并行收集器,追求搞吞吐量,高效利用CPU。吞吐量=用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效得利用CPU
    时间,可以尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景
  4. Serial Old 收集器(标记-整理算法):老年代单线程收集器。Serial收集器的老年代版本
  5. Parallel OLd 收集器(标记-整理算法):老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本
  6. CMS (Concurrent Mark
    Sweep)收集器(标记清除算法):老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发/低停顿的特点,追求最短GC回收停顿时间
    。 在启动JVM 的参数加上 ’XX:+UseConcMarkSweepGC‘来指定使用CMS垃圾回收器
  7. G1 (Garbage
    FIrst)收集器(标记-整理算法):Java堆并行收集器,G1收集器是jdk1.7提供的一个新的收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或者老年代

1.8详细介绍一下CMS垃圾回收器?

CMS是英文Concurrent Mark-Sweep 的简称,是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度得应用上,这种垃圾回收器非常的合适。 在启动JVM 的参数加上 ’XX:+UseConcMarkSweepGC‘来指定使用CMS垃圾回收器
CMS使用的是标记-清除得算法实现得,所以在gc得时候会产生大量的内存碎片,当剩余的内存不足以满足程序运行要求时,系统将会出现Concurrent Mode Failure ,临时CMS会采用Serial Old回收器进行垃圾清除,此时的性能将会被降低

1.9 新生代和老年代垃圾回收器的区别?

新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;
老年代回收器一般采用的是标记整理算法进行垃圾回收

1.10 简述分代垃圾回收器时怎么工作的?

分代回收器有2个分区:老年代和新生代 ,新生代默认得空间占比总空间得1/3 ,老年代得默认占比是2/3
新生代使用的是复制算法,新生代里有3个分区:eden /To Survivor /From Survivor 它们的默认占比是8:1:1 执行流程如下:

  • 把Eden + From Survivor 存活的对象放入To Survivor 清空Eden 和From Survivor 分区
  • From Survivo 和To Survivor 分区交换 , From Survivo变To Survivor ,To
    Survivor 变 From Survivor

每次在 From Survivor 到To Survivor移动时都存活的对象,年龄就+1,当年龄到达15(默认的配置是15)时,升级为老年代。大对象也会直接进入老年代
老年代当空间的占用达到某个值之后就会触发全局垃圾回收器,一般使用的标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整个执行流程。

内存分配策略

1.11 简述Java内存分配与回收策率以及Minor Gc 和Major GC?

所谓的自动内存管理,最终要解决的也就是内存分配和内存回收两个问题。前面介绍了内存回收我们来聊聊内存分配
对象的内存分配通常在Java堆上(随着虚拟机优化技术的诞生,某些场景下也会在栈上分配,后面会详细介绍),对象的分配主要在新生代的Eden区,如果启动了本地线程缓冲,将按照线程优先在TLAB上分配。少数情况也会直接在老年代上分配。总的来说分配规则不是百分百固定的,其细节取决于哪一种垃圾收集器组合以及虚拟机相关参数有关,但是虚拟机对于内存的分配还是会遵循以下规则:

对象优先在Eden区分配
多数情况,对象都在新生代Eden区分配。当Eden区分配没有足够的分配空间进行分分配时,虚拟机将会发起一次Minor GC .如果本次GC后还是没有足够的空间,则将启用分配担保机制在老年代中分配内存。
这是我们提到的Minor GC,如果你仔细观察过GC日常,通常我们还能从日志中发现Major GC/Full GC
Minor GC 是指发生在新生代的GC,因为Java对象大多都是朝生夕死,所有Minor GC非常的频繁,一般回收速度也非常的快
Major GC/Full GC 指发生在老年代的GC ,出现Major GC 通常会伴随着至少一次Minor GC ,Major GC 的速度通常会比Minor GC慢10倍以上。

大对象直接进入老年代
所谓的大对象是指需要大量的连续内存空间的对象,频繁出现大对象是致命的,会导致在内存还有不少空间的情况下提前触发GC以及获取足够的连续空间来安置新对象。
前面我们介绍过新生代使用的是标记-清除算法来处理垃圾回收的,如果大对象直接在新生代分配就会导致Eden区和两个survivor之间发生大量的内存复制。因此大对象都会直接在老年代进行分配

长期存活的对象将进入老年代
虚拟机采用分代收集的思想来管理内存,那么内存回收时就必须判断哪些对象应该放在新生代,哪些对象应该放在老年代。因此虚拟机给每个对象定义了一个对象的年龄的计算器,如果对象在Eden区出生,并且能够被survivor容纳,将被移动到survivor空间中,这时设置对象年龄为1.对象在survivor区每【熬过】一个Minor GC年龄就加1,当年龄达到一定程度(默认15)就会被晋升到老年代

常用的JVM调优的参数都有哪些?
-Xms2g : 初始化堆大小为 2g
-Xmx2g : 堆最大内存为2g
-XX:NewRatio=4 :设置 年轻的和老年代的内存比例为1:4
-XX:SurvivorRatio=8 : 设置新生代Eden和Survivor比例为8:2
-XX:+UseParNewGC : 指定使用ParNew +Serial Old垃圾回收器组合
-XX: +UseParallelOldGC :指定使用 ParNew + ParNew old 垃圾回收器组合
-XX :+UseConcMarkSweepGC :指定使用CMS + Serial Old 垃圾回收器组合
-XX:+PrintGC : 开启打印gc信息
-XX:+PrintGCDetails : 打印gc详细信息

本人最近新建了微信公众号,会不定期更新知识点,欢迎您各位小伙伴一起学习!

请添加图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值