金三银四跳槽季(五)Java基础

1、HashMap和ConcurrentHashMap的区别

HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。

ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁。

ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。

2、HashTable和ConcurrentHashMap的区别

它们都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map

3、String,StringBuffer和StringBuilder的区别

1、运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String
2、线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的。

适用场景分析:

  • String:适用于少量的字符串操作的情况
  • StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
  • StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

4、Java内存模型:
Java虚拟机规范中将Java运行时数据分为六种。

内存模型 描述
程序计数器 是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器,互不影响,该区域为“线程私有”。
Java虚拟机栈 线程私有的,与线程生命周期相同,用于存储局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型,还有对象的引用。
本地方法栈 跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务。
Java堆 所有线程共享的一块内存区域,对象实例几乎都在这分配内存。
方法区 各个线程共享的区域,储存虚拟机加载的类信息,常量,静态变量,编译后的代码。
运行时常量池 代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用。

5、 类加载器工作机制:

  1. 装载:将Java二进制代码导入jvm中,生成Class文件。
  2. 连接:a)校验:检查载入Class文件数据的正确性 b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用
  3. 初始化:对类的静态变量,静态方法和静态代码块执行初始化工作。
    双亲委派模型:类加载器收到类加载请求,首先将请求委派给父类加载器完成 用户自定义加载器->应用程序加载器->扩展类加载器->启动类加载器。

6、JDK和CGLIB生成动态代理类的区别:

JDK动态代理只能针对实现了接口的类生成代理(实例化一个类)。此时代理对象和目标对象实现了相同的接口,目标>对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类(没有实例化一个类),覆盖其中的方法 。

Spring AOP应用场景
性能检测,访问控制,日志管理,事务等。
默认的策略是如果目标类实现接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。

7、强引用,软引用和弱引用的区别

引用 区别
强引用 用的最广。我们平时写代码时,new一个Object存放在堆内存,然后用一个引用指向它,这就是强引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
软引用 如果一个对象只具有软引用,则内存空间足够时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。(备注:如果内存不足,随时有可能被回收。) 只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
弱引用 弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。每次执行GC的时候,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
虚引用 虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

参考:https://blog.csdn.net/lovesomnus/article/details/47103035

8、Java对象在内存中的状态

状态 描述
可达的/可触及的: ava对象被创建后,如果被一个或多个变量引用,那就是可达的。即从根节点可以触及到这个对象。其实就是从根节点扫描,只要这个对象在引用链中,那就是可触及的。
可恢复的: Java对象不再被任何变量引用就进入了可恢复状态。在回收该对象之前,该对象的finalize()方法进行资源清理。如果在finalize()方法中重新让变量引用该对象,则该对象再次变为可达状态,否则该对象进入不可达状态
不可达的: Java对象不被任何变量引用,且系统在调用对象的finalize()方法后依然没有使该对象变成可达状态(该对象依然没有被变量引用),那么该对象将变成不可达状态。当Java对象处于不可达状态时,系统才会真正回收该对象所占有的资源。

9、判断对象死亡的两种常用算法

算法 描述
引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。但是,主流的java虚拟机并没有选用引用计数算法来管理内存,其中最主要的原因是:它很难解决对象之间相互循环引用的问题。
根搜索算法:(jvm采用的算法) 设立若干种根对象,当任何一个根对象(GC Root)到某一个对象均不可达时,则认为这个对象是可以被回收的。

10、垃圾回收算法

算法 描述
标记-清除算法 标记阶段:先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象;清除阶段:清除所有未被标记的对象。
复制算法:(新生代的GC) 将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,然后清除正在使用的内存块中的所有对象。
标记-整理算法:(老年代的GC) 标记阶段:先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。整理阶段:将将所有的存活对象压缩到内存的一端;之后,清理边界外所有的空间
分代收集算法: 存活率低:少量对象存活,适合复制算法:在新生代中,每次GC时都发现有大批对象死去,只有少量存活(新生代中98%的对象都是“朝生夕死”),那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成GC。存活率高:大量对象存活,适合用标记-清理/标记-整理:在老年代中,因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-清理”/“标记-整理”算法进行GC。

1、详细jvm内存模型

2、讲讲什么情况下回出现内存溢出,内存泄漏?

3、说说Java线程栈

4、JVM 年轻代到年老代的晋升过程的判断条件是什么呢?

5、JVM 出现 fullGC 很频繁,怎么去线上排查问题?

6、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?

7、类的实例化顺序

8、JVM垃圾回收机制,何时触发MinorGC等操作

9、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的

10、各种回收器,各自优缺点,重点CMS、G1

11、各种回收算法

12、OOM错误,stackoverflow错误,permgen space错误

猜你喜欢

转载自blog.csdn.net/dreamsunday/article/details/79977518