Java知识点之JVM

1、Java虚拟机内存区域的划分以及作用详解

在这里插入图片描述

程序计数器

(1)也称为PC寄存器。Java文件被编译成class字节码最终解释成机器码,在JVM中,多线程通过轮流切换来获取CPU时间片,因此,在任意时刻,一个CPU的内核只会执行一条指令,即一个线程对应着一个程序计数器,程序计数器是线程中私有的,不能共享的。
(2)程序计数器主要存储一段字节码,这段字节码记录的是当前线程下一条需要执行指令的字节码地址

本地方法栈

本地方法栈和Java虚拟机栈类似,区别只不过是Java栈是为执行Java方法服务的,而本地方法栈是为执行本地方法服务的,实现该方法的代码可能是c或c++,反正不一定是Java代码

虚拟机栈

虚拟机栈描述的Java方法执行的内存模型,每个方法在执行的同时,都会创建一个栈帧来存放存放局部变量表、操作数表、动态链接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程
在这里插入图片描述
(1)对于方法中的局部变量,1.如果是基本数据类型,那么其值存放于虚拟机栈中;2.如果是引用对象类型,那么其地址存放在虚拟机栈中,对象的实例存放在堆中
(2)对于类(对象)中的变量(全局变量),1.如果是基本数据类型,那么其值存放在堆中;2.如果是引用对象类型,那么其声明的变量同样的会有一个对象地址和实例,均存放于堆中

所有线程共享的一块内存区域,Java虚拟机所管理的内存最大的一块,该内存区域的唯一目的就是存放对象实例。同时堆也是垃圾收集器管理的主要区域,很多时候被称为“GC堆”

方法区

在方法区中有一个非常重要的部分就是运行时常量池,他是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来,当然并非class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法

2、请简单描述一下JVM加载class文件的原理是什么?

(1)JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader是一个重要的Java运行时组件。它负责在运行时查找和装入类文件的类。
(2)Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。类装载的方式有隐式装载和显式装载。
隐式装载:程序在运行过程中当碰到new等方式生成对象时,隐式调用类加载器加载对应的类到JVM中
显式装载:通过class.forName()等方法,显式装载需要的类
(3)Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(像是基类)完全加载到jvm中,至于其他类,则在需要的时候才加载。这当然就是为了节省内存开销
(4)当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。
在这里插入图片描述

3、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?

(1)Java虚拟机是一个可以执行Java字节码的虚拟机进程
(2)Java与平台无关其实是Java字节码与平台无关。Java源文件被编译成Java字节码,Java字节码在Java虚拟机中被解释成机器码,所以,在不同的平台,只要有Java虚拟机环境,就可以把字节码解释成对应平台的机器码

4、JVM最大内存限制多少?

堆内存分配

JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4.默认空余内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般配置-Xms、-Xmx相等以避免在每次GC后调整堆的大小
在这里插入图片描述

非堆内存分配

JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。

VM最大内存

首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系 统下为2G-3G),而64bit以上的处理器就不会有限制了。

5、JVM是如何实现线程的?

(1)线程是比进程更轻量级的调度执行单位。线程可以把一个进程的资源分配和执行调度分开。一个进程里可以启动多个线程,多个线程可共享该进程的资源(内存地址,文件IO等),又可以独立调度。线程是CPU调度的基本单位。
(2)Java虚拟机的多线程是通过线程轮流切换分配处理执行时间的方式来完成的,在任何一个确定的时刻,一个处理器只会执行一个程序中的一条指令。因此为了线程切换后能恢复到正确的执行位置,每个线程都需要一个独立的程序计数器,各个线程间的程序计数器互不影响。所以,对于单核处理器,通过快速切换线程中的指令来达到多线程

6、请问什么是Java内存模型?

(1)Java内存模型(简称JMM),JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储了该线程以读/写共享变量的副本
(2)本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化
在这里插入图片描述

7、请列举一下,在JAVA虚拟机中,哪些对象可作为ROOT对象?

(1)虚拟机栈中的引用对象
(2)方法区中类静态属性引用的对象
(3)方法区中常量引用对象
(4)本地方法栈中JNI引用对象

8、GC中如何判断对象是否需要被回收?

(1)即使在可达性分析算法中不可达的对象,也并非是“非回收不可”的,这时候它们暂时处于“等待”阶段,要真正宣告一个对象回收,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。(即意味着直接回收)
(2)如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃
(3)finalize()方法是对象逃脱回收的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中跳出回收——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了

9、请简单描述一下类的加载过程

在这里插入图片描述

加载

加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的入口。注意这里不一定非要从一个class文件中获取,这里既可以从zip包中读取(jar或war包),也可以在运行时计算生成(动态代理),也可以由其他文件生成(比如将JSP文件转换成对应的Class文件)

验证

这一阶段主要目的是为了确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

准备

准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。注:public static int v = 8080,在准备阶段的初始值为0,将v赋值为8080是在程序被编译之后,存放于类构造器方法中;但如果是public static final int v = 8080,在编译阶段会为v生成ConstantValue属性,在准备阶段虚拟机会根据ConstantValue的属性将v赋值为8080

解析

解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。符号引用就是class文件中的:CONSTANT_Class_infoCONSTANT_Field_infoCONSTANT_Method_info等类型的常量

初始化

(1)初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其他操作都由JVM主导。到了初始阶段,才开始真正执行类中定义的Java程序代码
(2)初始化阶段是执行类构造器方法的过程。方法是由编译器自动收集类中的类变量的赋值操作和静态语句块中的语句合并而成的。虚拟机会保证方法执行之前,父类的方法已经执行完毕。ps: 如果一个类中没有对静态变量赋值也没有静态语句块,那么编译器可以不为这个类生成()方法。
注意以下几种情况不会执行类初始化
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值