Java面试之JVM

本章主要记录一些jvm相关的面试题目,平时对这方面不太注重,也是边学边记

内存区域

1. 说一下 JVM 的主要组成部分及其作用?

类加载器:负责把.class字节码文件加载到内存中,
运行时数据区:JVM在运行时对该Java进程占用内存进行逻辑划分
本地库接口:调用不同的语言,来扩充java的功能
,执行引擎:将字节码指令解释/编译为对应平台上的本地机器指令(将高级语言翻译为机器语言);

2. 运行时执行顺序?

java文件编译后变为class字节码,然后类加载器将其放进jvm中,在jvm中,堆内存内创建一个java.lang.class对象,类封装在其中(jvm的执行过程:jvm启动类装载器,类装载器则会寻找.class文件并装载到jvm中,jvm对.class文件进行解释成二进制后,操作系统执行二进制和底层硬件平台进行交互)

3. 说一下 JVM 运行时数据区

一个堆两个栈一个区一个程序计数器,
java堆:各个线程共享,几乎所有变量实例都在这里分配内存;
java虚拟机栈:虚拟机用来存储局部变量表,操作数栈,动态链接,方法出口灯;
本地方法栈:虚拟机调用本地方法栈
方法区:存储一些类的信息,编译后的代码
程序计数器:行号,一些程序执行时的代码顺序

4. 深拷贝和浅拷贝

深浅拷贝,或者复制,其区别就在于是否开辟新的内存区域,浅拷贝就只是新建一个指向旧内存区域的指针,深拷贝就建立了新的内存区域,这样的好处在于删去内存区域时不会产生别的指针错误

5. 说一下堆栈的区别?

物理地址:堆不连续而栈连续
内存区域:堆在运行时动态确认内存大小,栈需要在编译时就确认,栈小于堆
存放内容:堆一般是变量,数组一类数据存储,栈是操作数,对象,返回结果一类,这些东西连续,偏运行
可见性:堆对整体可见,栈对单个线程可见,生命周期与线程同步

6. 队列和栈是什么?有什么区别?

这两个都类似数据结构里的队列和栈,队列是先进先出,可以在头尾操作,栈是先进后出,只能在栈顶操作

7. Java 中提供的几种对象创建方式,创建流程

使用new,class的newInstance方法以及constructot的newInstance方法,这三种调用构造器;而反序列化和clone不调构造器
创建流程:首先检查类是否加载,然后检查内存是否规整,然后检查并发问题,最后初始化,设置对象信息, 执行init

8.为对象分配内存的两种方式

内存碰撞:如果内存规整,就按照对象大小在其后划分一段供使用
空闲列表:内存不规则,虚拟机用一个列表记录内存使用情况,查询划分给对象

9. 处理并发安全问题的方式

CAS同步和本地线程分配缓冲
所谓并发安全,主要就出现在两个对象分配内存中的冲突一类的错误,而解决办法就是同步或者上锁
第一种就是cas和失败重试进行同步,保证原子性,第二种就是tlab(方法缩写),每个线程分配时在一块预先给的tlab内存里进行,如果用完后需要分配一块新的tlab,就上同步锁

10. 对象的访问定位方式

两种方法,
句柄,句柄指向指针,指针指向对象内存,就算对象地址移动,也不需要移动句柄
直接指针,直接指向对象地址,如果移动就需要重分配这些指针,优势在于速度快

11. Java会存在内存泄漏吗?请简单描述

通常gc就会对内存泄露进行处理,也就是对象生命周期已经结束后由gc回收,但如果别的还没结束的对象引用了一个已经结束的对象,那就因为短引用被长持有而无法回收短,也就是内存泄露

12. 简述Java垃圾回收机制,为什么要gc

java内,一般不需手动回收内存,gc垃圾回收一般是在空间不足且虚拟机空闲时,去扫描那些已经不使用的内存进行释放,因为开发人员可能会遗忘释放内存操作,或者手动释放出现冲突,所以由java自动gc

13. 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法

主动通知虚拟机进行垃圾回收
创建对象后,gc就开始监控,一般使用有向图,对那些不可达的,就执行回收,system类里有gc方法,但未必会执行

14. Java 中都有哪些引用类型?

强软弱虚引用四种,分别是不会被gc,内存不足时gc,下次gc,给gc返回一个消息

15. 怎么判断对象是否可以被回收?

计数器法,初始是0,引用一个加一,删一个减一,是0就可以回收
引用链法,从root往下找,若找到一个没有一个指向它的节点,就判断可以gc

16. JVM中的永久代中会发生垃圾回收吗,

一般不会,但超过永久代大小时,会进行完全垃圾回收,需要设置合适的永久代大小,但java8已经用本地数据区代替了永久代

17. 说一下 JVM 有哪些垃圾回收算法

标记清除:标记出无用的然后清除,缺点是会产生内存碎片
复制:内存均分两块,一块存,一块空闲,要gc时直接把有用的搬到另一块,原来的全删
标记整理:将有用的归并整理,边界外的删掉
分代:分新生代,老生代,新生代复制,老生代标记整理

18. JVM 有哪些垃圾回收器

在这里插入图片描述上面三种是复制算法(新生代),下面msc,po,g1是标记整理,CMS是标记清除

19. 简述分代垃圾回收器是怎么工作的

新生代老生代之间过渡通过年龄计算,先进入新生代,其中分为Eden,tosurvivior,from survivor,ef两种向t中移动,存活一次年龄加一,年龄超过15进入老生代,大对象则直接进入老生代,老生代达到一定大小就fullgc,一般是标记整理

20. 简述java内存分配与回收策略

对象优先在新生代eden区分配,大对象直接进入老生代,对象存活超过一定时间周期必然进入老生代

21. 类装载的执行过程

加载查找class文件,验证class类的正确性,准备静态变量分配内存,解析内存引用指向,初始化静态变量和代码块
java类加载机制,虚拟机把数据加载为类文件,验证,准备解析,初始化,形成可执行的java文件

22. JVM加载Class文件的原理机制

java的字节码都需要加载到虚拟机中才能运行,通常不需要关心,但使用反射的话,就需要了解,分显隐两种加载看,显式是class.forname手动加载,隐式就还是new对象时装到虚拟机里

23. ThreadLocalMap的理解,实现原理

ThreadLocal目的是隔离不同线程所使用的变量,它可以将某一个变量隔离在某个线程内,其它的线程无法访问和使用这个变量。
原理:
定义了一个ThreadLocalMap内部类,使用的是Map的键值对方式来存取数据,key是ThreadLocal类的实例对象,value为传值
创建新的ThreadLocal对象,调用set()或get()方法时,也就是调用了ThreadLocalMap来进行操作
使用ThreadLocal时,线程所使用的变量是独享的(私有的变量副本),其他线程无法访问,在使用过后(线程结束),这些变量会被GC回收

24. sleep和wait的区别。

1)sleep是线程类(Thread)的方法;wait是Object类的方法
2)sleep是使线程休眠,不会释放对象锁;wait是使线程等待,释放锁
3)调用sleep进入阻塞状态;调用wait进入就绪状态

25. synchronized关键字的用法,优缺点。

修饰方法
修饰一个代码块(一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞,当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。 )
指定要给某个对象加锁
修饰一个类

26. volitile关键字的作用,原理。

volatile 作用 :
1.保证内存可见性 即不会出现数据脏读的现象,从而保证数据的“可见性”
2.禁止进行指令重排序(即保证有序性)
volatile 的实现原理:
1.将当前处理器缓存行的数据写回系统内存
2.这个写回内存的操作会使得其他CPU缓存的该内存地址的数据无效。

27. ABC三个线程如何保证顺序执行。

1、 使用线程池 将所有线程放入一个队列 ,保证顺序输出
2、使用 wait(), synchronized(同步锁) 轮询机制 到谁了 谁输出

28. 创建线程有几种方式?

常见有四种 继承Thread 类; 实现Runnable 接口; 实现Callable 接口; 使用Executors 工具类创建线程池

29. jdk自带几种线程池?

四种:
Executors.newCachedThreadPool()
创建一个可缓存线程的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
Executors.newFixedThreadPool()
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
Executors.newScheduledThreadPool()
创建一个定长线程池,支持定时及周期性任务执行。
Executors.newSingleThreadExecutor()
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

30. 线程池创建时要考虑几种因素

配置好线程池参数(7个):
1. corePoolSize:线程池中的常住线程数
2. maximumPoolSize:线程池中能够容纳同时执行的最大线程数,必须>= 1
3. keepAliveTime:多余的空闲线程额存活时间,当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程会被销毁知道只剩下corePoolSize个线程位置。
4. unit:keepAliveTime的单位。
5. workQueue:任务队列,被提交但尚未执行的任务。
6. threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认即可。
7. handler:拒绝策略,表示当队列满了,并且工作线程>=线程池的最大线程数(maximumPoolSize),这是如何来拒绝请求执行的runnabel的策略
同时还有一些注意点:
线程池不使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让开发者更加明确线程池的运行规则,规避资源耗尽的风险

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值