阿里腾讯面试题目3

1、个人参与度最高的一个项目,怎么设计的模块?

2、常见的 JVM GC 算法

在探讨 Java 垃圾回收机制之前,我们首先应该记住一个单词:Stop-the-World。Stop-the-world 意味着 JVM 由于要执行 GC 而停止了应用程序的执行,并且这种情形会在任何一种 GC 算法中发生。当 Stop-the-world 发生时,除了 GC 所需的线程以外,所有线程都处于等待状态直到 GC 任务完成。事实上,GC 优化很多时候就是指减少 Stop-the-world 发生的时间,从而使系统具有 高吞吐 、低停顿 的特点。
1、标记清除算法
标记-清除算法分为标记和清除两个阶段。该算法首先从根集合进行扫描,对存活的对象对象标记,标记完毕后,再扫描整个空间中未被标记的对象并进行回收,如下图所示。


标记-清除算法的主要不足有两个:
效率问题:标记和清除两个过程的效率都不高;
空间问题:标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,因此标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。


2、复制算法
  复制算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这种算法适用于对象存活率低的场景,比如新生代。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。该算法示意图如下所示:


事实上,现在商用的虚拟机都采用这种算法来回收新生代。因为研究发现,新生代中的对象每次回收都基本上只有 10%左右的对象存活,所以需要复制的对象很少,效率还不错。实践中会将新生代内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间 (如下图所示),每次使用 Eden 和其中一块 Survivor。当回收时,将 Eden 和 Survivor 中还存活着的对象一次地复制到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。HotSpot 虚拟机默认 Eden 和 Survivor 的大小比例是 8:1,也就是每次新生代中可用内存空间为整个新生代容量的 90% ( 80%+10% ),只有 10% 的内存会被“浪费”。


3、标记整理算法
  复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的是,如果不想浪费 50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都 100%存活的极端情况,所以在老年代一般不能直接选用这种算法。标记整理算法的标记过程类似标记清除算法,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存,类似于磁盘整理的过程,该垃圾回收算法适用于对象存活率高的场景(老年代),其作用原理如下图所示。


标记整理算法与标记清除算法最显著的区别是:标记清除算法不进行对象的移动,并且仅对不存活的对象进行处理;而标记整理算法会将所有的存活对象移动到一端,并对不存活对象进行处理,因此其不会产生内存碎片。标记整理算法的作用示意图如下:


4、分代收集算法
  对于一个大型的系统,当创建的对象和方法变量比较多时,堆内存中的对象也会比较多,如果逐一分析对象是否该回收,那么势必造成效率低下。分代收集算法是基于这样一个事实:不同的对象的生命周期(存活情况)是不一样的,而不同生命周期的对象位于堆中不同的区域,因此对堆内存不同区域采用不同的策略进行回收可以提高 JVM 的执行效率。当代商用虚拟机使用的都是分代收集算法:新生代对象存活率低,就采用复制算法;老年代存活率高,就用标记清除算法或者标记整理算法。Java 堆内存一般可以分为新生代、老年代和永久代三个模块,如下图所示:


1).新生代(Young Generation)
  新生代的目标就是尽可能快速的收集掉那些生命周期短的对象,一般情况下,所有新生成的对象首先都是放在新生代的。新生代内存按照 8:1:1 的比例分为一个 eden 区和两个 survivor(survivor0,survivor1)区,大部分对象在 Eden 区中生成。在进行垃圾回收时,先将 eden 区存活对象复制到 survivor0 区,然后清空 eden 区,当这个 survivor0 区也满了时,则将 eden 区和 survivor0 区存活对象复制到 survivor1 区,然后清空 eden 和这个 survivor0 区,此时 survivor0 区是空的,然后交换 survivor0 区和 survivor1 区的角色(即下次垃圾回收时会扫描 Eden 区和 survivor1 区),即保持 survivor0 区为空,如此往复。特别地,当 survivor1 区也不足以存放 eden 区和 survivor0 区的存活对象时,就将存活对象直接存放到老年代。如果老年代也满了,就会触发一次 FullGC,也就是新生代、老年代都进行回收。注意,新生代发生的 GC 也叫做 MinorGC,MinorGC 发生频率比较高,不一定等 Eden 区满了才触发。
2).老年代(Old Generation)
  老年代存放的都是一些生命周期较长的对象,就像上面所叙述的那样,在新生代中经历了 N 次垃圾回收后仍然存活的对象就会被放到老年代中。此外,老年代的内存也比新生代大很多(大概比例是 1:2),当老年代满时会触发 Major GC(Full GC),老年代对象存活时间比较长,因此 FullGC 发生的频率比较低。
3).永久代(Permanent Generation)
  永久代主要用于存放静态文件,如 Java 类、方法等。永久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些 class,例如使用反射、动态代理、CGLib 等 bytecode 框架时,在这种时候需要设置一个比较大的永久代空间来存放这些运行过程中新增的类。
5、小结

作者:CodeKing2017
链接:https://www.jianshu.com/p/3fc4450e1bbd
来源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3、对于 SpringBoot 自动配置原理说一遍

Spring Boot 启动的时候会通过@EnableAutoConfiguration 注解找到 META-INF/spring.factories 配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以 AutoConfiguration 结尾来命名的,它实际上就是一个 JavaConfig 形式的 Spring 容器配置类,它能通过以 Properties 结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而 XxxxProperties 类是通过@ConfigurationProperties 注解与全局配置文件中对应的属性进行绑定的。
————————————————
版权声明:本文为 CSDN 博主「圣斗士 Morty」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014745069/java/article/details/83820511

你可能感兴趣的:(阿里腾讯面试题目3)