0
点赞
收藏
分享

微信扫一扫

每日基础面试题了解

天涯学馆 2022-04-26 阅读 105
面试

JDK、JRE、JVM之间的区别

  • JDK(Java SE Development Kit),java标准开发包,它提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等

  • JRE(Java Runtime Environment),java运行环境,用于运行Java的字节码文件。JRE中包括了JVM以及JVM所需要的类库,普通用户而只需安装JRE来运行Java程序,而程序开发者必须安装JDK来编译、调试程序。

  • JVM(Java Virtual Mechinal),Java虚拟机,是JRE的一部分,它是整个Java实现跨平台的最核心的部分,复杂运行字节码文件

    我们写Java代码,用txt文本就可以写,想要运行,就需要先编译乘字节码,那就需要编译器,而JDK就包含了编译器javac,编译之后的字节码,想要运行就需要一个可以执行字节码的程序,这个程序就叫JVM(Java虚拟机),专门用于执行Java字节码的。

​ 如果我们要开发Java程序,那就需要JDK,因为要编译Java源文件

​ 如果我们只是想运行已经编译好的Java字节码文件,也就是*.class文件,那么就需要JRE

​ JDK中包含JRE,JRE中包含JVM

​ 另外,JVM在执行Java字节码时,需要把字节码解释为机器指令,而不同操作系统的机械指令是有可能不一样的,所以导致不同操作系统上的JVM是不一样的,所以我们在安装JDK时需要选择操作系统

​ 另外,JVM是用来执行Java字节码的,所以凡是某个代码编译之后是Java字节码,那就都能在JVM上运行,比如Apache Groovy Scala and Kotlin等等

完整的JDK体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ERzY0MK-1650953222786)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220421172114198.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sySt1HXk-1650953066645)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220421172421782.png)]

汇编语言要在不同平台输出helloworld,要开发不同的汇编代码

image-20220421173052198

java虚拟机调优主要是调节内存区域

一般new出来的对象都存放在堆里 对象

栈(线程)放局部变量数据,只要一个线程一运行,Java虚拟机就会给它分配一个专属的内存空间,那么这个内存空间就叫做(线程栈)

(只要Java中有线程运行,虚拟机就分配一块内存,用于存放局部变量)

在这里插入图片描述

栈帧 一个方法对应一块栈帧内存区域

栈帧里除了局部变量 还有操作数栈 动态链接 方法出口

image-20220421174820727

当方法调用一结束,内部的局部变量会销毁释放掉就是出栈 分配内存就是入栈

先调用的方法先分配内存,后调用的方法后分配内存 后调用的方法会先结束

javap -c xxx.java>xxx.txt 反编译

int a=1 = 0:iconst_1 1:iconst_1

程序计数器:每一个线程都独有的 值: 方法区那个内部的内存地址

Java开发人员为什么要设计一个程序计数器:当一个更高优先级的线程让它先执行,先头的线程就处于挂起,等待高优先级的线程运行完,再开始先头的线程,程序计数器就可以找到先头线程执行到哪一步再接着执行。

image-20220421183933536

局部变量0相当于this

iload_1从局部变量1中装载int类型值 放在操作数栈里

iadd执行int类型的加法 会从操作数栈栈顶弹出最外边两个数做加法运算,再把结果压回栈

imul执行int类型的乘法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dxDjAuAH-1650953066648)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220421200903777.png)]

方法执行在栈中有内存地址,这个内存地址就放在动态链接里,需要调用方法就根据动态链接中的内存地址找方法区方法

方法出口 调用方法返回的信息都保存在方法出口 再根据储存信息知道返回main中哪一行代码继续执行

jdk8以后方法区改为元空间(常量+静态变量+类信息)

image-20220421203654253

指针指向我们的堆 math,user是内存地址指向math,user 箭头黑色箭头指向

native本地方法 底层有实现,实现不是用Java写的,C++;本地方法栈也会分配一块内存给本地方法栈

image-20220421204314550

new出来的对象优先是放在Eden区,当Eden区放不下了,Java虚拟机会让字节码执行引擎来 垃圾回收线程 minor gc

Java底层回收垃圾的算法 可达性分析算法

GC Roots根节点:线程栈的本地变量、静态变量、本地方法栈的变量等等

从Java虚拟机中寻找被引入用数据,从引用数据到最上层都标记为非垃圾 ,将这些引用数据全部加入survivor s0中,剩余大量对象在Eden中就会被销毁释放,minor gc会回收整个年轻代空间

(将“GC Roots”对象作为起点,从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未标记的对象就是垃圾对象)

当对象在s0s1中反复转换,每次minor gc都会加1,minor gc>15时,对象将被复制到老年代

Major Gc=young Gc,只回收老年代

image-20220421210855589

image-20220421211255181

这串代码会内存溢出,因为内存会不断被这个新new出来的对象填充,调用minor gc会发现,new出来的新对象被heapTests对象引用,heapTests又被ArrayList引用,所以这个对象无法被回收。

JDK自带调优工具jvisualvm,在cmd中输入该命令 重点看Visual GC查看当前运行中堆的变化

metaspace元空间 old老年代 Eden年轻代

image-20220421212425022

Arthas调优工具 阿里巴巴Arthas Java诊断工具 支持JDK6+,采用命令行交互模式,可以方便的定义和诊断线上程序运行问题。

java虚拟机调优:减少gc 最核心减少full gc

当老年代当中对象放满了,不会立即销毁释放,会先执行full gc(通过字节码执行引擎执行full gc对整个堆进行垃圾回收)老年代装满了放不下了就会内存溢出(OOM)

当执行gc垃圾回收时,Java虚拟机会停止用户线程 STW(停止用户线程)

为什么设计STW机制,STW会影响用户体验

反证法
进行垃圾回收时,gc都在向下找引用对象,用户线程也在进行,这时候也大大影响性能,暂停用户线程,先进行垃圾回收,效果可能会更好。

image-20220422111456104

image-20220422114104179

image-20220422115031437

调优:让生命周期非常短的对象,在年轻代就被回收,不要到老年代中调用fullgc

不同垃圾收集器底层停顿不一样

image-20220424142859625

==和equals方法的区别

  • ==:如果是基本数据类型,比较值,如果是引用类型,比较的是引用地址
  • equals:具体看各个类重写equals方法之后的比较逻辑,比如string类,虽然是引用类型,但是string类重写了equals方法,方法内部比较的是字符串的各个字符是否全部相等
String s ="123";
s.equals("xxx");
进入equals内看源码
string类的equals

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xxgPcVTW-1650953066654)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220422202917730.png)]

User user =new User();
user.equals()
进入equals内看源码
object类的equals方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YHcUczmL-1650953066655)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220422203250636.png)]

重载和重写的区别

  • 重载(overload):在一个类中,同名的方法如果有不同参数列表(比如参数类型不同、参数个数不同)则视为重载
  • 重写(override):从字面上看,重写就是重写写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承父类的方法,但有时子类并不想原封不动的继承父类的某个方法,所以在方法名,参数列表,返回类型都相同(子类中方法的返回值可以是父类中返回的子类)的情况下,对方法进行修改,这就是重写,但要注意子类方法的访问修饰权限不能小于父类的

hashCode()与equals之间的关系

在Java中,每个对象都可以调用自己的hashCode方法得到自己的哈希值(hashcode),相当于对象的指纹信息,通常来说世界上没有完全相同的两个指纹,但是在Java中做不到这么绝对,但是我们人可以利用hashcode来做一些提前判断,比如:

  • 如果两个对象的hashcode不相同,那么两个对象肯定不同的两个对象

  • 如果两个对象的hashcode相同,不代表这两个对象一定是同一个对象,也可能是两个对象

  • 如果两个对象相等,那么他们的hashcode就一定相同

    在Java的一些集合类的实现中,在比较两个对象是否相等时,会根据上面的原则,会先调用对象的hashcode()方法得到hashcode进行比较,如果hashcode不同,就可以直接认为这两个对象不相同,如果hashcode相同,那么就会进一步调用equals()方法进行比较。而equals()方法,就是用来最终确定两个对象是不是相等,通常equals()方法的实现会比较重,逻辑比较多,而hashcode()主要就是得到一个哈希值,实际上就一个数字,相对而言比较轻,所以在比较两个对象时,通常就会优先根据hashcode相比较一下

    所以我们就需要注意,如果我们重写了equals方法,那么就要注意hashcode方法,一定能保证能遵循上述规则。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2PgbRgo-1650953066656)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220422203655921.png)]

得到两个user对象,去得到他们各自的name属性进行比较 如果两个对象name属性相等,那么这两个对象相等

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDT0QzhH-1650953066656)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220422203843662.png)]

结果为null

查看get方法,只有当两个对象的hashcode值相同时在调用equals方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mxl3w4ol-1650953066657)(C:\Users\靓仔在此\AppData\Roaming\Typora\typora-user-images\image-20220422204058776.png)]

并发编程三要素

(1)原子性

原子性指的是一个或多个操作,要么全部执行并且在执行过程中不被其他操作打断,要么全部执行,要么全部不执行。

(2)可见性

可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果

(3)有序性

有序性,即程序的执行顺序按照代码的先后顺序来执行

实现可见性的方法有哪些

synchronized 或者Lock:保证同一个时刻只有线程获取锁执行代码,锁释放之前把最新的值刷新到主内存,实现可见性

多线程的价值

(1)发挥多核cpu的优势

多线程,可以真正发挥出多核cpu的优势来,达到充分利用cpu的目的,采用多线程的方式去同时完成几件事情而不互相干扰

(2)防止阻塞

从程序运行效率的角度来看,单核cpu不但不会发挥多线程的优势,反而会因为在单核cpu上运行多线程导致线程上下文的切换,而降低程序整体的效率。但是单核cpu我们还是要应用多线程,就是为了防止阻塞。试想如果单核 CPU 使用单线程,那么只要这个线程阻塞了,比方说远程读取某个数据吧,对端迟迟未返回又没有设置超时时间,那么你的整个程序在数据返回回来之前就停止运行了。多线程可以防止这个问题,多条线程同时运行, 哪怕一条线程的代码执行读取数据阻塞,也不会影响其它任务的执行

(3)便于建模

这是另外一个没有这么明显的优点了。假设有一个大的任务A,单线程编程,那么就要考虑很多,建立整个程序模型比较麻烦。但是如果把这个大的任务分解成几个小任务,任务B,任务C,任务D,分别建立程序模型,并通过多线程分别运行这个几个任务,那么就会简单很多

举报

相关推荐

0 条评论