2KB项目,专业的源码交易网站 帮助 收藏 每日签到

Go 语言的手工内存管理

  • 时间:2019-01-23 18:31 编辑:2KB 来源:2KB.COM 阅读:303
  • 扫一扫,手机访问
  • 分享
摘要:
Go 英文原文:Manual Memory Management in Go

介绍

注:如果您对这篇文章有不同观点,欢迎指正 - 我并不是这方面的专家。

我们从大量的 go 用户中收集了有关于使用 defer 和 panic 的性能统计。不像其它的 APM/error 记录公司,我们的重点不是告诉你有一个问题,而是实际解决问题的方法。这就是为什么我们要使用 go。

这使我们看出对大家来说什么是好的,坏的和丑的。

当你的项目中隐藏了一个大问题时,如果你只是来回查看通常是不能发现它的,直到你对它进行测试。

许多性能问题可能已经存在了数周。

通常这些问题大部分可以简单的通过 pprof 等方法分析目标程序来解决掉。

一旦你怀疑一个地方是错误的,你就应该先看看这个(pprof)。

然而,有时候,在经过几天都不能找到问题源头的时候,程序猿就会开始抱怨一切。

是数据库的问题!

框架的问题!

是 cat(计算机辅助程序)的问题!(猫?。。。)

是垃圾回收器的问题!

每当这个点上,团队里就会有个家伙跳出来说,他使用的某某语言更好(-_-!,那样如样你不是个软件工程师,你将被他搞得晕头转向。

我这里不讨论关于语言、cats(又是猫?。。)或者框架。

我只是想引导大家讨论更有效率的方案。

我确实想说说垃圾回收器。它是在大多数语言中常常被提及的性能问题,但是,如果问题随手就可以解决掉,那它也就不会引起人们的关注了。

反对垃圾回收器的争论,在相当长的一段时间内,有快速赶超硬编码汇编的争论。当然,如果你了解需要知道的一切,关于目标编译器,目标架构,目标操作系统等,那么你选择一两项内容做优化是说得通的,但是,这基本上是说,你比一些最好的编译器作者还要更胜一筹。你可能具备这样的能力。

然而, 这是相当高的要求。

实际上,有许多人们觉得相当不错的垃圾回收器,如 azul 的内存回收器.

背景

“C程序员认为内存管理太重要了,不能由电脑自己处理。 Lisp 的程序员认为内存管理太重要了,不能由用户来处理。“ —— Bjarne Stroustrup

要开始使用 - 大部分现代编程语言都使用自动化的垃圾收集机制。

无论是 Java 或是 C# 都有垃圾收集器。并且,一些解释型语言也有。

约翰·麦卡锡(John McCarthy)1958年在归途中发明了一种叫“垃圾回收器”的东西。这是在成功发射 Sputnik 的第二年。之后他还发明了别的东西。

所以,这个概念已经有相当长的时间了,但一些开发者似乎仍然对这个概念感到不安。为什么呢?

要回答这个问题,我们应该看看各种方法的内存管理。

内存管理的方法

这里有一些内存管理内存的方法,你可以:

* 在编译时分配所有的内存

* 手动管理内存

* 自动管理内存

对于我们的定义,我们认为垃圾是使用完毕的已分配内存。同时,也为了这篇博客,唯一的差别在于,垃圾可以由程序员手动清理(或者不清理),或者由编程语言自动清理。

在管理内存的过程中,存在许多问题。其中,有些问题是显而易见的,有些问题则不容易发觉;有些问题不容易解决,而另一些问题甚至无人意识到它的存在。

这通常只是想当然,因为--你通常拥有一个垃圾回收器!!:)

管理内存中的问题:

* 引用不再使用的内存

* 使用未分配内存的指针

* 分配内存但从不释放

* 使用释放了内存的指针

* 没有分配足够的内存

* 分配内存大小错误

* 分配或者释放内存太快或者太慢

* 在内存中存储数据之前加载内存

* 安全的从内存中删除敏感数据

* 内部碎片

* 外部碎片

实际上--安全行业统计过,关于内存管理的错误使用,涉及到数十亿美元。这显然是一个问题。

基本的内存管理操作

内存管理在计算机科学中有它的独特之处,但是,这里有两种最常用和最重要的操作:

分配:这是分配一块内存给指定请求的操作,同时保证分配器不会将此内存分配给其它地方,除非你说不。

释放/重用:这就是当你说--这块内存我已经使用完了,你可以按照你觉得合适的方式,自由的处理它了。内存并未“删除”。内存也并未“释放”到空中,或者其它地方。所做的,只是内存做了标记,这样,下一次请求的时候,它就可以重新使用了。

关于内存管理的错误假设

预留 vs. 分配

许多人困惑的一件事情是,分配内存和预留内存的差别。Go 语言 一开始就预留了一大块内存(reserves a large chunk of memory right off the bat) 。这样做有很多原因--其中之一是,连续vs.非连续的内存映射。你希望尽可能的减少碎片。

对于我们而言,我们定义预留是对 malloc 函数的一次调用,然而,当我们决定使用这片内存的时候,内存分配才真正发生。只要存在未预留的内存空间,我们就可以随心所欲的调用 malloc 函数。但是,当我们使用内存,并消耗完它的时候,我们就会得到内存不足(OOM)的错误信息。

操作系统中断

开发者认为如果他们可以分配和释放内存,他们的程序就不会因 GC 调用而中断和变慢。

如果上述假设是真实的,那么这种逻辑的问题所在是他们忘记了操作系统本身可以阻塞内存的分配,调度程序切换到其他任务, 而且所有的设备驱动程序都有中断处理。你的代码不是孤立存在的,有太多的因素公导致它产生暂停。

内存释放不一定是免费的

使用一个好的 GC 确实可以减少内存分配时间。同时释放内存并不意味着立即释放内存块,通过你用的任何版本的 malloc 都会把它放在一个释放列表里 -  这样可以帮助阻止碎片化。 

当然,释放内存有时间并不是免费的,它可以是随机的,你需要分页,导致糟糕的 IO。试想做大量的小内存分配,你会导致大量的碎片,为了避免崩溃不得不重新分配堆栈大小。

碎片

我已经提到碎片好几次了 - 让我告诉你一个简单的例子。

比方说,我们有一个地方可以动态分配内存。有4个我们可以访问的槽。但是,每次我们请求内存时,我们只能获取2个插槽。


我们第一次分配,我们抢到了前两个槽。然后,我们断言我们之后不再需要第一个槽,所以我们“删除”了。好吧,太棒了。现在看起来是这样的。


现在一个大的数据库作业来了,我们还需要一个槽。太糟糕了,我们的分配机制只允许我们一次获取2个槽 - 所以会发生什么?我们得到了接下来的两个槽。现在,我们已经分配了四分之三的,即使我们只用了其中的2个。这样继续下去,直到剩下的全都是我们不能夹这些已经分配的槽中间使用很多的空闲缝隙。

这是让我们抓狂的碎片。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。


2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务

  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【计算机/互联网|】Nginx出现502错误(2020-01-20 21:02)
【计算机/互联网|】网站运营全智能软手V0.1版发布(2020-01-20 12:16)
【计算机/互联网|】淘宝这是怎么了?(2020-01-19 19:15)
【行业动态|】谷歌关闭小米智能摄像头,因为窃听器显示了陌生人家中的照片(2020-01-15 09:42)
【行业动态|】据报道谷歌新闻终止了数字杂志,退还主动订阅(2020-01-15 09:39)
【行业动态|】康佳将OLED电视带到美国与LG和索尼竞争(2020-01-15 09:38)
【行业动态|】2020年最佳AV接收机(2020-01-15 09:35)
【行业动态|】2020年最佳流媒体设备:Roku,Apple TV,Firebar,Chromecast等(2020-01-15 09:31)
【行业动态|】CES 2020预览:更多的流媒体服务和订阅即将到来(2020-01-08 21:41)
【行业动态|】从埃隆·马斯克到杰夫·贝佐斯,这30位人物定义了2010年代(2020-01-01 15:14)
联系我们

Q Q: 7090832

电话:400-0011-990

邮箱:7090832@qq.com

时间:9:00-23:00

联系客服
商家入住 服务咨询 投拆建议 联系客服
0577-67068160
手机版

扫一扫进手机版
返回顶部