深入理解Java虚拟机(四)之垃圾回收相关概念

System.gc()的理解

  • 在默认情况下,通过System. gc()或者Runtime . getRuntime () .gc()的调用,会显式触发FullGC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。
  • 然而System. gc()调用附带一个免责声明,无法保证对垃圾收集器的调用。
  • JVM实现者可以通过System. gc ()调用来决定JVM的GC行为。而一般情况下,垃圾回收应该是自动进行的,无须手动触发,否则就太过于麻烦了。在一些特殊情况下,如我们正在编写一个性能基准,我们可以在运行之间调用System.gc()。

用户线程的暂停:Stop-The-World(STW)

垃圾回收工作是在垃圾回收线程中执行的,在很多情况下,执行垃圾回收工作,或是执行垃圾回收其中 某一步骤时需要暂停用户线程,也就是Stop-The-World(STW)。

  • 垃圾回收首先是要经过标记的。对象被标记后就会根据不同的区域采用不同的收集方法。
  • 垃圾回收线程标记好对象时,用户线程在并发执行时,可能会将该对象重新加入“引用链”,垃圾回收时就会回收这个不该回收的对象,出现问题。
  • 在类加载完成的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。这样,GC在扫描时就可以直接得知这些信息了。这些特定的位置称为安全点(Safepoint)。
  • 程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。
  • GC发生时让所有线程暂停,即让所有线程“跑”到最近的安全点上再停顿下来,有两种方案可供选择:
  1. 抢先式中断(PreemptiveSuspension):不需要线程的执行代码主动去配合,在GC发生
    时,首先把所有线程全部中断,如果发现有线程中断的地方不在安全点上,就恢复线程,让
    它“跑”到安全点上。现在几乎没有虚拟机实现采用抢先式中断来暂停线程从而响应GC事件。
  2. 主动式中断(Voluntary Suspension):是当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。轮询标志的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。

在垃圾收集器的学习中,有两个概念需要先说明:

  • 并行(Parallel) : 指多条垃圾收集线程并行工作,用户线程仍处于等待状态。
  • 并发(Concurrent) : 指用户线程与垃圾收集线程同时执行(不一定并行,可能会交替执行),用户程序继续运行,而垃圾收集程序在另外一个CPU上。

安全点与安全区域

安全点:

程序执行时并非在所有地方都能停顿下来开始GC, 只有在特定的位置才能停顿下来开始GC,这些位置称为“安全点(Safepoint) ”.

SafePoint的选择很重要,如果太少可能导致GC等待的时间太长,如果太频繁可能导致运行时的性能问题。大部分指令的执行时间都非常短暂,通常会根据“是否具有让程序长时间执行的特征”为标准。比如:选择些执行时间较长的指令作为Safe Point, 如方法调用、循环跳转和异常跳转等。

如何在GC发生时,检查所有线程都跑到最近的安全点停顿下来呢?

  • 抢先式中断:(目前没有虚拟机采用了)
    首先中断所有线程。如果还有线程不在安全点,就恢复线程,让线程跑到安全点。
  • 主动式中断:
    设置一个中断标志,各个线程运行到Safe Point的时 候主动轮询这个标志,如果中断标志为真,则将自己进行中断挂起。

安全区域

Safepoint机制保证了程序执行时,在不太长的时间内就会遇到可进入GC的Safepoint。但是,程序“不执行”的时候呢?例如线程处于Sleep
状态或Blocked 状态这时候线程无法响应JVM的中断请求“走”到安全点去中断挂起:JVM也不太可能等待线程被唤醒。对于这种情况,就需要安全区域(Safe Region)来解决。

安全区域是指在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的。我们也可以把Safe Region看做是被扩展了的Safepoint。

引用

强引用

指在程序代码之中普遍存在的,类似Object obj=new Object()这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

软引用(内存不足即回收)

用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK 1.2之后,提供了SoftReference类来实现软引用。

弱引用(发现即回收)

用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2之后,提供了WeakReference类来实现弱引用。

虚引用

也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用(PhantomReference)关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

Java的语言类型

Java属于混合型语言(Mixed Mode),即有编译期编译的过程,也存在运行期解释和编译的过程。

在编译期通过javac编译器编译java文件,运行期通过解释器(Interpreter)和即时编译器(Just In Time
Compiler,JIT编译器)配合完成解释、编译工作。

猜你喜欢

转载自blog.csdn.net/qq_41552331/article/details/106648963