jvm常见的知识点

1.垃圾回收

java中三个区域程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,也随线程而灭。java的堆和方法去则不一样。一个借口的多个实现类需要的内存不一样,一个方法的分支需要的内存也不一样。只有运行期间时才会知道创建哪些对象。

2.引用计数器

  • 给对象添加了一个引用计数器。每当有一个地方引用它,计数器就加1.当引用失效的时候计数器就减1.任何时刻计数器变为0的对象就是不能再被使用了。
  • 虚拟机并没有因为两个对象互相引用就不回收他们,说明虚拟机不是通过计数算法来判断对象是否存活。

3.可达性分析

通过一些列成为“gc root”的对象作为起始点,从这些节点开始向下搜素。搜索走过的路径称为引用链。当一个对象到gc roots没有任何引用链相连的时候证明这个对象时不可达的。

4.gc roots的对象的种类

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

5.引用的类型

  • 强引用指的是类似于object a=new object().只要强引用还存在,垃圾回收期永远不会被回收掉。
  • 软引用:有用但是非必须的对象。在系统将要发生内存溢出异常之前,会把这些对象列入回收范围。
  • 弱引用:比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。无论内存是否足够,当垃圾收集器工作的时候都会回收掉只被弱引用关联的对象。
  • 虚引用:最弱的引用关系。无法通过一个虚引用取得一个对象实例。引入他的唯一目的是能在这个对象被收集器收集的时候收到一个系统通知。

6.任何一个对象的finalize()方法只会被系统自动调用一次,如果面临下一次回收,它的finalize()方法就不再执行了。

7.方法区回收(虚拟机中的永久代)

  • 一般认为方法区不要求垃圾收集,因为在方法区垃圾收集的性价比一般比较低
  • 永久代的垃圾收集主要有两方面内容:废弃常量和无用的类。
  • 1.可以以常量池中的字面量的回收为例子。

8.无用的类的要求与条件(方法区的问题)

  • 该类所有的实例都已经被回收,堆上不存在该类的任何实例。
  • 加载该类的classloader已经被回收
  • 该类对应的java.lang.class对象没有任何地方被引用,无法再任何地方通过反射访问该类的方法。

决定是否使用是否对类进行回收-Xnoclassgc
-verbose:class以及 -XX+TraceClassLoading、-XX+TraceClassUnLoading查看类加载和卸载信息。

9.几种垃圾收集的思想?

  • 标记清除:首先标记处所有需要回收的对象,在标记完成后统一回收所有标记的对象。这种算法有两种问题:一个是效率问题,另一个是空间碎片太多,会导致以后程序运行的过程中无法分配较大的对象而不得不提前触发另一次垃圾收集动作。
  • 复制算法:将可用内存划分为大小相等的两块。每次智世勇一块。当一块用完了,就将存活的对象复制到另一块上。然后对整个半区进行回收。

现在的商业虚拟机采用这种算法回收新生代(在堆上的)。

  • 标记整理:让后续存活的对象向一端移动,然后直接清理掉端边界以外的内存。
  • 分代收集法:新生代里的对象大多死的快,就使用复制算法。而老年带中因为对象存活率高、没有额外空间对它担保分配,就必须使用"标记–清理"算法来进行回收。

10.hotspot的算法实现

  • 枚举根节点,从可达性分析对时间的敏感体现在GC停顿上。因为分析工作要在一个确保一致性的快照中进行。因此GC执行的时候必须停顿所有JAVA执行线程。
  • 虚拟机使用一组成为OOPMAP的数据结构直接得知哪些地方存放对象引用。在类加载完成的时候,hotspot就会把对象内什么偏移量上是什么类型数据记录下来。在jit编译过程中也会特定记录下栈和寄存器中哪些是引用。
    *虚拟机中的所有收集器
    1.新生代:serial parnew parallel seavenge
    2.老年带:cms serial old parallelold

parnew 是serial的多线程改进。
并行:垃圾线程并行工作,此时用户线程处于等待。
并发:用户线程与垃圾收集线程同时执行,用户程序继续运行而垃圾收集运行于另一个cpu上。

11.理解GC日志

  • gc/full gc:垃圾回收的他停顿类型。
  • defnew/perm/tenured:gc发生的区域
  • 3324k->152k:gc前该内存区域使用量和适用后的容量。
  • 0.0025925:表示内存区域gc所占用的时间。

12.对象优先在eden分配。

  • 堆中包括新生代和老年代(tenuredgen)
  • 新生代中包含:eden,survivor、survivor三个个区域

14.serial垃圾收集器

不同垃圾收集器的运用场景也不同。

  • 最基本的,单线程的垃圾回收器。
  • 当有四个线程运行的时候,当开始利用该垃圾收集进行垃圾回收的时候。四个线程停止,开始垃圾回收线程。回收之后,再四个线程再继续进行。

15.allel scavenge收集器

  • 复制算法(新生代收集器)
  • 多线程收集器
  • 达到一个可控制的吞吐量(cpu用于运行用户代码的时间与cpu消耗的总时间的比值。)
  • 吞吐量:(执行用户代码的时间)/(执行用户代码的时间+垃圾回收所占用的时间)

-xx:maxgcpausemillis:最大垃圾收集器停顿的时间。 -xx:gctimeratio吞吐量大小,范围在0到100之间。

16.收集器 concurrent mark sweep

  • 初始标记
  • 并发标记(并发的含义是此时也有用户的线程在运行)
  • 重新标记
  • 并发清理

优点:并发收集、低停顿
缺点:占用大量的cpu、无法处理浮动垃圾、空间碎片。

17.G1收集器

  • 初始标记
  • 并发标记
  • 最终标记
  • 筛选回收
  • 特点:并行与并发、分代收集、空间整合(基于标记整理的方法)可预测的停顿。
  • 可预测的停顿的模型建立。g1垃圾收集器对java堆的内存布局与其他收集器有很大区别。它将整个java堆分为多个大小相等的独立区域。新生代和老年代不再是物理隔离了。G1可以避免在整个堆中进行全区域的垃圾收集。G1跟踪垃圾堆积的回收价值,优先回收代价最大的region(G1的原因)
  • Remember set的存在使垃圾收集器避免对全堆进行扫描。当程序发现本region内存在对引用类型的写操作的瘦。会产生一个写终端,检查所引用的对象是否处于相同region之中。如果不在一个region中,则把引用记录到被引用对象所属的region的remember set中。对region进行垃圾回收的时候。同时利用gc root和remember set就可以保证不对全堆扫描也不会有遗漏。

18.Minor GC和Full GC有什么区别?

  • 新生代GC(Minor GC):发生在新生代的垃圾收集动作,比较频繁,回收速度比较快。
  • 老年代GC(major gc/full gc):发生在老年代的GC,至少会伴随一次minor gc。这个gc速度更慢。

19.-xx:pretenureSizeThreshold的作用?

  • 这个参数设置为3MB,超过3MB的对象都会直接在老年代进行分配。

20.-xx:maxTenuringThreshold设置?

1 .对象在eden出生,并经过第一次minor gc仍然存活,并被移动到survivor空间,此时对象的年龄为1.
2 .对象在survivor区中每熬过一次minor gc,年龄就增加1岁。当它的年龄增加到一定程度之后,就会晋升到老年代中。

21.空间分配担保

  • 在minor gc之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象空间,此时的minor gc是安全的。
  • 如果不成立,虚拟机会查看handlepromotionFailure。如果允许会检查老年代中最大可用连续空间是够大于历次晋升到老年代对象的平均大小。
  • 如果大于,尝试进行一次minor,尽管还是有风险的。
  • 如果小于,此时要进行一次Full Gc。

原因:minor gc之后survivor空间无法容纳新生代存活的对象,因此无法容纳的对象直接进入老年代。由于每次多少对象活下来是无法确定的,所以只好取前每一次回收到老年代对象容量的平均值作为经验值,决定是否进行full gc。

猜你喜欢

转载自blog.csdn.net/qq_22152499/article/details/89069483