您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

什么是垃圾回收?程序的自动内存管理

时间:2023-05-31 13:55:16  来源:51CTO  作者:李睿

译者 | 李睿

审校 | 重楼

本文对垃圾回收进行介绍,其中包括垃圾回收算法的概述,以及垃圾回收是如何在一些流行的编程语言(包括JAVAPython/ target=_blank class=infotextkey>Python)中实现的。在讨论这个问题之前,首先考虑垃圾回收机制的优点和缺点。为什么它是内存分配错误的常见解决方案?以下从不使用垃圾回收的C和C++等语言中内存管理的风险开始。

C/ C ++中内存管理的风险

内存分配问题只是C/C++常见问题的一个子集,这些问题会导致潜在的错误和漏洞,但它们是一个很大的子集,很难追踪和修复。内存分配错误包括以下场景:

  • 未能释放已分配的内存,最终可能会耗尽系统中的所有内存,不仅会使程序崩溃,还会使计算机崩溃。
  • 在释放内存之后,尝试通过指针读取或写入缓冲区,可能会产生随机结果(也称为悬空指针)。
  • 双重释放内存块,这可能会导致内存管理器崩溃,最终导致程序甚至整个系统崩溃。

其他常见的C/C++漏洞包括缓冲区溢出和字符串操作,它们可以用数据覆盖代码。“有趣”的部分是网络攻击者对数据进行处理,使其成为恶意可执行代码,然后设法运行代码。

很多人说这种情况不会再发生了,因为在保护模式系统中有单独的代码和数据段。不幸的是,这种情况仍然会发生。例如,一个程序在字符串中构造SQL语句,然后将其发送到数据库执行,这通常会创建SQL注入漏洞。当然,在避免SQL注入漏洞方面有一些良好的记录的最佳实践,但是在数据库客户端中不断出现这类错误,表明不是每一位程序员都会遵循最佳实践。

垃圾回收:具有缺陷的纠正方法

使用垃圾回收可以完全消除主要的内存分配和回收问题,但这是有代价的。最大的问题是垃圾回收器的开销;当垃圾回收器运行时出现不可预测的暂停;并且当服务器进程停止时增加了延迟。后一个问题经常出现在基于Java的服务器程序中。

垃圾回收的开销可能很大,涉及内存和性能之间的权衡。开发人员Matthew Hertz和Emery D.Berger在2005年发表的一篇论文指出:“具有五倍内存的苹果风格的分代回收器具有非复制的成熟空间,与基于访问的显式内存管理的性能相匹配。而如果只有三倍的内存,回收器的运行速度比显式内存管理平均慢17%。然而,如果只有两倍的内存,垃圾回收的性能降低了近70%。当物理内存不足时,分页导致垃圾回收的运行速度比显式内存管理慢一个数量级。”

苹果风格的分代回收器是保守的垃圾回收器,更具攻击性的垃圾回收器有时可以用更少的内存表现得更好。

停滞和延迟意味着基于垃圾回收的语言对于需要最小化延迟的实时程序和高吞吐量服务器来说可能不是最优的。例如,在实时Lisp和实时Java方面已经有了一些尝试,所有这些尝试都修改或消除了垃圾回收器。

最近,一些Java和Scala服务器采用非垃圾回收的编程语言进行了重写,例如Scylla(用C++重写Cassandra)和Redpanda(用C++替换Kafka插件)。在“Scylla”和“Redpanda”中,与最初的服务器相比,已经显著减少了延迟。对于相同的负载,两者都需要更小的集群。

垃圾回收算法

垃圾回收有几十种算法,以下来看看一些最重要的算法及其显著特征。

引用计数

在引用计数中,程序将对资源的引用、指针或句柄的数量存储为分配资源的一部分,并在添加或删除引用时增加或减少计数。当引用计数为零时,资源可以被释放。内存垃圾回收只是引用计数的应用之一;它也用于系统对象、windows COM对象和文件系统块或文件的释放控制。

引用计数有两个主要的缺点:过于频繁的更新和循环引用。控制更新频率的一种方法是允许编译器对相关对象进行批处理。处理循环引用的一种方法是不定期运行跟踪垃圾以删除不可访问的循环,循环引用使计数不会达到零。

跟踪垃圾回收

跟踪垃圾回收是引用计数的主要替代方案,包括以下所有算法以及更多的算法。通常跟踪垃圾回收的思想是,跟踪过程从一些根对象(如当前局部变量、全局变量和当前函数参数)开始,并根据引用确定哪些对象是可访问的,然后对所有无法访问的对象进行垃圾回收。跟踪垃圾回收是如此普遍,有时简单地称之为垃圾回收。

标记和扫描

1960年发布的“naïve”标记和扫描算法可以追溯到John McCarthy开发的Lisp编程语言,它的工作原理是首先冻结系统,然后将从根集中可访问的所有对象标记为“正在使用”。第三步是清除所有内存并释放未标记为“正在使用”的任何块。最后,清除所有剩余内存块中的“正在使用”位,为下一次回收做准备,并允许系统继续执行。显然,这对于实时系统是不合适的。

标记和扫描的一种变体使用了三种“颜色”的内存块:白色块是不可访问的,如果算法结束时它们仍然在白色集合中,则将释放它们;黑色块可以从根访问,并且没有对白色集合中的对象的外向引用;灰色块可以从根访问,但还需要扫描对“白色”对象的引用。在算法完成后,灰色块全部进入黑色集合。通常情况下,初始标记将根引用的所有块放入灰色集合中,将所有其他块放入白色集合中。

三色标记算法分为三步:

(1)从灰色集合中选择一个对象,并将其移动到黑色集合中。

(2)将其引用的每个白色对象移动到灰色集合。这确保了该对象及其引用的任何对象都不能被垃圾回收。

(3)重复最后两个步骤,直到灰色集合为空。

当灰色集合为空时,所有白色块都可以释放。三色标记算法可以在程序运行时在后台执行;开销仍然存在,但它不会让“整个世界停止”。

复制回收

复制回收(又名半空间垃圾回收)的思想是将内存分为两个大小相等的区域,分别称为“从空间”和“到空间”。在空间中按顺序分配内存块,直到空间填满,然后执行回收。这交换了区域的角色,并将活动对象从“从空间”复制到“到空间”,在“到空间”的末尾留下一块空闲空间(对应于所有不可访问对象使用的内存)。

复制回收存在复杂性。最大的一个问题是,当复制数据块时,它们的地址会发生变化;一种解决方案是维护转发地址表。另一个主要问题是,复制集合所需的内存是标记和扫描所需内存的两倍。如果大部分内存是垃圾,复制回收比标记和扫描要快,但如果大部分内存可访问,则复制回收较慢。

标记和压缩

标记和压缩回收的本质是复制在单个内存空间内运行的回收。标记和压缩回收器扫描所有可访问的对象,并将它们压缩在堆的底部,这使得堆的顶部可供使用。标记和压缩回收的最大缺点是比较耗时。

分代回收

分代回收根据对象的年龄(也就是代)将堆划分为多个空间(通常是两个或三个)。一般来说,最近的对象比旧的对象更可能是垃圾,因此在大多数情况下扫描新对象以寻找垃圾,而不使用旧对象是有意义的。一些分代回收器在不同的代上使用不同的扫描频率或回收算法。

哪些编程语言使用垃圾回收?

自从John McCarthy在1958年开发Lisp编程语言以来,Lisp就一直在用于垃圾回收。Java、Scala、Python和.NET/C#都是流行的垃圾回收语言。其他垃圾回收语言包括相对年轻的Go、Ruby、D、OCaml和Swift,以及较老的语言Eiffel、Haskell、ML、Modula-3、Perl、Prolog、Scheme和Smalltalk。

Java、Python和.Net/C#是一些比较流行的实现垃圾回收的编程语言。Java虚拟机(JVM)实际上提供了四种不同的垃圾回收器:串行、并行、并发标记、扫描,以及第一个垃圾回收器G1GC。G1GC现在是Java中的默认值,它是一个区域化和世代并行压缩收集器,可实现软实时目标。

Python(特别是标准的CPython实现)将引用计数与仅专注于清理容器对象的三级代收集相结合。.NETCLR(公共语言运行时)使用三级生成标记和紧凑收集算法。CLR还将内存对象分为两个堆,一个用于大型对象(85000字节或更高),另一个用于小型对象;大型对象堆通常不会被压缩,只是被标记和扫描,但如果需要可以被压缩。

结论

正如人们所看到的,处理垃圾回收的方法有很多,其中大多数都有自己的用途。更成熟的垃圾回收实现结合了多种算法,并且多年来进行了大量调优,以尽量减少延迟。

原文标题:What is garbage collection? Automated memory management for your programs作者:Martin Heller



Tags:垃圾回收   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Java垃圾回收器的工作原理及监视不再使用对象的机制
Java作为一门面向对象的编程语言,具有自动内存管理的特性。这意味着开发人员无需手动分配和释放内存,而是由Java虚拟机的垃圾回收器负责管理。垃圾回收器通过监视程序中不再使...【详细内容】
2023-12-27  Search: 垃圾回收  点击:(134)  评论:(0)  加入收藏
Java垃圾回收器对循环引用对象的处理机制
循环引用的定义与问题循环引用是指两个或多个对象之间形成了相互引用的关系,形成了一个环状结构。例如,对象A引用了对象B,而对象B又引用了对象A,它们之间形成了一个循环引用。这...【详细内容】
2023-12-25  Search: 垃圾回收  点击:(114)  评论:(0)  加入收藏
GC是什么?为什么要GC?JVM 垃圾回收算法有哪些?
Major GC 老年代区域的垃圾回收,老年代空间不足时,会先尝试触发Minor GC。Minor GC之后空间还不足,则会触发Major GC,Major GC速度比较慢,暂停时间长。图片1 Java垃圾回收机制(GC...【详细内容】
2023-12-07  Search: 垃圾回收  点击:(223)  评论:(0)  加入收藏
揭秘Java性能调优的奥秘:垃圾回收调优与线程池优化
Java性能调优是提高应用程序性能和效率的重要一环,其中GC调优和线程池优化是两个关键方面。下面将揭秘Java性能调优的奥秘,并详细介绍GC调优和线程池优化的方法。一、GC调优垃...【详细内容】
2023-11-23  Search: 垃圾回收  点击:(239)  评论:(0)  加入收藏
深入理解Java的垃圾回收机制与内存管理
在Java编程中,垃圾回收机制和内存管理是非常重要的概念。Java的垃圾回收机制可以自动管理内存,使得开发者无需手动分配和释放内存,极大地简化了程序的开发和维护。本文将深入探...【详细内容】
2023-11-14  Search: 垃圾回收  点击:(209)  评论:(0)  加入收藏
Python开发者的必备知识:内存管理与垃圾回收
Python是一种高级编程语言,因其简洁而强大而备受欢迎。然而,正如其他编程语言一样,Python也面临着内存管理的挑战。在Python中,垃圾回收是一项关键任务,用于自动释放不再使用的内...【详细内容】
2023-11-08  Search: 垃圾回收  点击:(244)  评论:(0)  加入收藏
理解JAVA的垃圾回收机制
当Java垃圾收集器(GC)运行时,它作为一个守护线程在后台运行,用于为用户线程提供服务或执行JVM任务。它定期检查堆内存中的所有对象,并识别那些不再被程序的任何部分引用的对象(也...【详细内容】
2023-09-26  Search: 垃圾回收  点击:(387)  评论:(0)  加入收藏
Go语言之垃圾回收机制
什么是三色标记法 三色标记法是一种用于垃圾回收的算法,被广泛应用于各类编程语言的垃圾回收器中,包括Go语言。这种算法将对象划分成三种颜色: 白色:表示对象是垃圾,可以被释放...【详细内容】
2023-08-28  Search: 垃圾回收  点击:(274)  评论:(0)  加入收藏
什么是垃圾回收?程序的自动内存管理
译者 | 李睿审校 | 重楼本文对垃圾回收进行介绍,其中包括垃圾回收算法的概述,以及垃圾回收是如何在一些流行的编程语言(包括Java和Python)中实现的。在讨论这个问题之前,首先考...【详细内容】
2023-05-31  Search: 垃圾回收  点击:(311)  评论:(0)  加入收藏
Python 垃圾回收机制中的引用计数
Python 中的 __del__ 魔法方法,也被称为对象的终结者,是一个在对象即将被从内存中移除之前被调用的方法。它实际上并不做从内存中删除对象的工作,我们将在后面看到它是如何发生...【详细内容】
2023-03-27  Search: 垃圾回收  点击:(143)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(6)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条