推广 热搜: csgo  vue  angelababy  2023  gps  新车  htc  落地  app  p2p 

Java 垃圾回收机制详解及实例代码

   2023-07-27 网络整理佚名1140
核心提示:垃圾回收机制详解下面是用C写的一个手动管理内存的简单例子:自动垃圾回收早期的一种实现便是引用计数。在上面的C++代码中,我们还得显式地声明我们需要使用内存管理。有几种方法可以解决这一问题,比如说使用特殊的“弱”引用,或者使用一个特殊的算法回收循环引用。缺点就是应用程序的线程需要被暂停才能完成回收,如果引用一直在变的话你是无法进行计数的。

Java垃圾收集机制详解

乍一看,垃圾收集的作用正如其名称所暗示的那样——查找并删除垃圾。 事实上恰恰相反。 垃圾收集跟踪所有仍在使用的对象,然后将剩余的对象标记为垃圾。 考虑到这一点,让我们深入了解一下这种称为“垃圾收集”的自动内存回收在 JVM 中是如何实现的。

手动管理内存

在介绍现代版本的垃圾收集之前,让我们简单回顾一下手动显式分配和释放内存的日子。 如果忘记释放内存,则内存无法重复使用。 这块内存被占用但没有使用。 这种情况称为内存泄漏。

下面是一个用 C 语言编写的手动内存管理的简单示例:

int send_request() {
  size_t n = read_size();
  int *elements = malloc(n * sizeof(int));
  if(read_elements(n, elements) < n) {
    // elements not freed!
    return -1;
  }
  // …
  free(elements)
  return 0;
}

正如您所看到的,您很容易忘记释放内存。 内存泄漏曾经是一个非常常见的问题。 你只能通过不断修复自己的代码来对抗它们。 因此,需要有一种更优雅的方式来自动释放无用的内存,以减少人为错误的可能性。 这个自动化过程也称为垃圾收集(简称GC)。

智能指针

自动垃圾收集的早期实现是引用计数。 您知道每个对象被引用了多少次,当计数器达到零时,该对象就可以被安全回收。 C++的共享指针是一个非常著名的例子:

int send_request() {
  size_t n = read_size();
  stared_ptr> elements 
       = make_shared>();
  if(read_elements(n, elements) < n) {
    return -1;
  }
  return 0;
}

我们使用的会记录这个对象被引用的次数。 如果传递计数,计数就会加一;如果超出范围,计数就会减一。 一旦该计数达到 0,底层对应项将被自动删除。 当然,这只是一个例子,因为有读者指出这在现实中不太可能发生,但作为演示已经足够了。

自动内存管理

在上面的C++代码中,我们还必须明确声明我们需要使用内存管理。 那么如果所有对象都使用这个机制呢? 这实在是太方便了,开发者不需要考虑清理内存的事情。 运行时会自动知道哪些内存不再使用,然后释放它。 换句话说,它会自动回收垃圾。 第一代垃圾收集器于 1959 年在 Lisp 中引入,此后该技术不断发展。

引用计数

我们刚刚用 C++ 共享指针演示的思想可以应用于所有对象。 Perl、PHP等很多语言都使用这种方法。 这可以很容易地用一张图来解释:

绿色云代表程序中仍在使用的对象。 从技术上讲,这有点像正在执行的方法中的局部变量,或者静态变量。 对于不同的编程语言情况可能会有所不同,所以这不是我们关注的重点。

蓝色圆圈代表内存中的对象,您可以看到有多少对象引用它们。 灰色圈出的对象不再被任何人引用。 因此,它们是垃圾对象,可以被垃圾收集器清理掉。

看起来不错,对吧? 确实如此,但这里有一个重大缺陷。 很容易出现一些孤立的环,其中的对象不在任何域中,但相互引用,因此引用计数不为 0。下面是一个示例:

你看,红色部分实际上是应用程序不再使用的垃圾对象。 由于引用计数的缺陷,会出现内存泄漏。

有几种方法可以解决这个问题,例如使用特殊的“弱”引用,或者使用特殊的算法来回收循环引用。 前面提到的Perl,以及PHP等语言,都使用类似的方法来恢复循环引用,但这超出了本文的范围。 我们将详细介绍 JVM 所采用的方法。

标记为删除

首先,JVM对对象可达性有更清晰的定义。 它不再像之前绿云一样模糊,而是对垃圾收集根对象(Roots)有非常明确和具体的定义:

JVM通过标记-删除算法记录所有可达(存活)对象,同时保证不可达对象的内存可以被重用。 这涉及两个步骤:

JVM中不同的GC算法,例如Mark+Copy、CMS都是该算法的不同实现,但阶段略有不同,概念上仍然对应于上面提到的两个步骤。

这个实现最重要的是不会再有泄漏的对象环:

缺点是需要挂起应用程序线程来完成回收,并且如果引用一直在变化,则无法计数。 这种应用程序暂停以便 JVM 可以进行清理的情况也称为 Stop The World 暂停 (STW)。 触发这种暂停的可能性有很多种,但垃圾收集应该是最常见的一种。

感谢您的阅读,希望对您有所帮助,感谢您对本站的支持!

 
反对 0举报 0 收藏 0 打赏 0评论 0
 
更多>同类资讯
推荐图文
推荐资讯
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报
Powered By DESTOON