JVM的垃圾回收机制是用来干嘛的?为什么要垃圾回收?

刘超 3月前 ⋅ 710 阅读   编辑

一、回顾

  在JVM中有哪些内存区域,分别都是用来干嘛的?分析了JVM中的几块内存区域分别都是干什么的,今天介绍一下垃圾回收的概念,但对垃圾回收不会切入过深,只是初步了解垃圾回收到底是什么,先来看一下昨天的一张图,回顾一下JVM中几块内存区域的作用。

    

  代码在运行的时候,起码有一个main线程会去执行所有的代码,当然也可能是你启动的别的线程。然后线程执行时必须通过自己的程序计数器来记录执行到哪一个代码指令了,另外线程在执行方法时,为每个方法都得创建一个栈帧放入自己的Java虚拟机栈里去,里面有方法的局部变量。最后就是代码运行过程中创建的各种对象,都是放在Java堆内存里的。

二、对象的分配与引用

  现在我们假设下面有一段代码,大概意思可以理解为"loadReplicasFromDisk"方法的执行,去磁盘加载需要的副本数据,然后创建"ReplicaManager"对象。代码如下所示

public class Kafka{
 public static void main(){
  loadReplicasFromDisk();
 }
 
 private static void loadReplicasFromDisk(){
  ReplicaManager replicaManager = new ReplicaManager();
  replicaManager.load();
 }
}

  结合我们之前理解过的JVM运行原理,以期通过动态的图来拆解一下上述代码的运行流程,首先一个main线程肯定会来执行main()方法里的代码,main线程自己是有一个Java虚拟机栈的,他会把main()方法的栈帧压入Java虚拟机栈,如下图

 

  接着main()方法里调用了loadRelicasFromDisk()方法,那么就会创建loadReplicasFromDisk()方法的栈帧,压入main线程的Java虚拟机栈里去,这个过程如下图:

 

  此时发现在loadReplicasFromDisk()方法里,有一个"replicaManager"变量,那么就会在loadReplicaFromDisk()方法对应的栈帧里,放入一个"replicaManager"变量,继续看下图

 

  接着发现在代码里创建一个"ReplicaManager"类的实例对象,此时就会在Java堆内存中分配这个实例对象的内存空间,同时,让loadReplicasFromDisk()方法的栈帧内的"replicaManager"局部变量去指向哪个Java堆内存里的ReplicaManager实例对象,大家看下图

 

  接下来,就会执行通过"replicaManager"局部变量引用的"ReplicaManager"实例对象去执行他的load()方法,去完成我们实现的业务逻辑。

三、一个方法执行完毕后会怎样?

  接着大家来回顾一下上面的代码

public class Kafka{
 public static void main(String[] args) {
  loadReplicasFromDisk();
 }
 
 private static void loadReplicasFromDisk(){
  ReplicaManager replicaManager = new ReplicaManager();
  replicaManager.load();
 }
}

  其实目前的图我们已将表述到了"replicaManager.load()"这行代码这里,那么现在有一个问题,如果这行代码执行结束了,此时会怎么样?

  一旦你的loadReplicasFromDisk()方法执行完毕,此时就会把loadReplicasFromDisk()方法对应的额栈帧从main线程的Java虚拟机栈里出栈,如下图所示

 

  此时一旦loadReplicasFromDisk()方法的栈帧出栈,那么大家会发现那个栈帧里的局部变量,"replicaManager",也就没有了,也就是说,没有任何一个变量去指向Java堆内存里的"ReplicaManager"实例对象了

四、我们创建的Java对象其实都是占用内存资源的

  我们可以发现,Java堆内存里的那个"ReplicaManager"实例对象已经没有人引用他了,该干的事儿都干完了,现在你还让他留在内存里干啥呢?毕竟内存资源是有限的。一般来说,我们会在一台机器上启动一个Java程序,机器的内存资源是有限的,比如就4个g的内存,然后我们启动的Java程序本质就是一个JVM进程,它负责运行我们的程序的代码,那么这个JVM进程本身也是会占用机器的部分内存资源,比如占用2G的内存资源,那么我们在JVM的Java堆内存中创建的对象,其实本质也是会占用JVM的内存资源的,比如"ReplicaManager"示例对象,会占用500字节的内存

  所以大家看到这里,心中应该无比明白的一个核心点:我们在Java堆内存里创建的对象,都是占用内存资源的,而且内存资源有限。看下面的图,感受会深一点

 

五、不再需要的那些对象该怎么处理?

  继续思考上面的图,既然"ReplicaManager"对象实例是不需要使用的,已经没有任何方法的局部变量在引用这个实力对象了,而且他还空占着内存的资源,那么我们应该怎么处理呢?答案呼之欲出:**JVM的垃圾回机制**

  JVM本身是有垃圾回收机制的,他是一个后台自动运行的线程,你只要启动一个JVM进程,他就会自带这么一个垃圾回收的后台线程,这个线程在后台不断检查jvm堆内存中的各个实例对象,还是给大家画一张图,来看看这个过程:

 

  如果某个实例对象没有任何一个方法的局部变量指向他,也没有任何一个类的静态变量,包括常量等地方在指向他。那么这个垃圾回收线程,就会把这个没有引用指向的"ReplicaManager"实例对象给回收掉,从内存里清除掉,让他不再占用任何内存资源,这样的话,这些不再被引用指向的对象实例,即JVM中的"垃圾",就会定期的被后台垃圾回收线程清理掉,不断释放内存资源,看下图:

 

  到此为止,相信大家跟上文章思路一路看下来,就很清晰明了。到底什么是JVM中的"垃圾"?什么又是JVM中的"垃圾回收"!


注意:本文归作者所有,未经作者允许,不得转载

全部评论: 0

    我有话说: