怎么优化go语言内存占用 go语言内存不断升高

vertxgo内存消耗对比

vertxgo的内存消耗要低于vert.x,因为它使用Go的优化机制,使其占用更少的内存。例如,它使用引用计数来确保变量的有效性,从而减少垃圾回收期间内存分配和释放等其他开销。此外,vertxgo还使用了GO语言的内存池,使得其内存使用率更低。由于Go语言的内存处理技术比其他语言更有效率,所以vertxgo的内存消耗会更低。

成都创新互联公司制作网站网页找三站合一网站制作公司,专注于网页设计,网站设计、成都网站制作,网站设计,企业网站搭建,网站开发,建网站业务,680元做网站,已为1000+服务,成都创新互联公司网站建设将一如既往的为我们的客户提供最优质的网站建设、网络营销推广服务!

Go语言中恰到好处的内存对齐

在开始之前,希望你计算一下 Part1 共占用的大小是多少呢?

输出结果:

这么一算, Part1 这一个结构体的占用内存大小为 1+4+1+8+1 = 15 个字节。相信有的小伙伴是这么算的,看上去也没什么毛病

真实情况是怎么样的呢?我们实际调用看看,如下:

输出结果:

最终输出为占用 32 个字节。这与前面所预期的结果完全不一样。这充分地说明了先前的计算方式是错误的。为什么呢?

在这里要提到 “内存对齐” 这一概念,才能够用正确的姿势去计算,接下来我们详细的讲讲它是什么

有的小伙伴可能会认为内存读取,就是一个简单的字节数组摆放

上图表示一个坑一个萝卜的内存读取方式。但实际上 CPU 并不会以一个一个字节去读取和写入内存。相反 CPU 读取内存是 一块一块读取 的,块的大小可以为 2、4、6、8、16 字节等大小。块大小我们称其为 内存访问粒度 。如下图:

在样例中,假设访问粒度为 4。 CPU 是以每 4 个字节大小的访问粒度去读取和写入内存的。这才是正确的姿势

另外作为一个工程师,你也很有必要学习这块知识点哦 :)

在上图中,假设从 Index 1 开始读取,将会出现很崩溃的问题。因为它的内存访问边界是不对齐的。因此 CPU 会做一些额外的处理工作。如下:

从上述流程可得出,不做 “内存对齐” 是一件有点 "麻烦" 的事。因为它会增加许多耗费时间的动作

而假设做了内存对齐,从 Index 0 开始读取 4 个字节,只需要读取一次,也不需要额外的运算。这显然高效很多,是标准的 空间换时间 做法

在不同平台上的编译器都有自己默认的 “对齐系数”,可通过预编译命令 #pragma pack(n) 进行变更,n 就是代指 “对齐系数”。一般来讲,我们常用的平台的系数如下:

另外要注意,不同硬件平台占用的大小和对齐值都可能是不一样的。因此本文的值不是唯一的,调试的时候需按本机的实际情况考虑

输出结果:

在 Go 中可以调用 unsafe.Alignof 来返回相应类型的对齐系数。通过观察输出结果,可得知基本都是 2^n ,最大也不会超过 8。这是因为我手提(64 位)编译器默认对齐系数是 8,因此最大值不会超过这个数

在上小节中,提到了结构体中的成员变量要做字节对齐。那么想当然身为最终结果的结构体,也是需要做字节对齐的

接下来我们一起分析一下,“它” 到底经历了些什么,影响了 “预期” 结果

在每个成员变量进行对齐后,根据规则 2,整个结构体本身也要进行字节对齐,因为可发现它可能并不是 2^n ,不是偶数倍。显然不符合对齐的规则

根据规则 2,可得出对齐值为 8。现在的偏移量为 25,不是 8 的整倍数。因此确定偏移量为 32。对结构体进行对齐

Part1 内存布局:axxx|bbbb|cxxx|xxxx|dddd|dddd|exxx|xxxx

通过本节的分析,可得知先前的 “推算” 为什么错误?

是因为实际内存管理并非 “一个萝卜一个坑” 的思想。而是一块一块。通过空间换时间(效率)的思想来完成这块读取、写入。另外也需要兼顾不同平台的内存操作情况

在上一小节,可得知根据成员变量的类型不同,其结构体的内存会产生对齐等动作。那假设字段顺序不同,会不会有什么变化呢?我们一起来试试吧 :-)

输出结果:

通过结果可以惊喜的发现,只是 “简单” 对成员变量的字段顺序进行改变,就改变了结构体占用大小

接下来我们一起剖析一下 Part2 ,看看它的内部到底和上一位之间有什么区别,才导致了这样的结果?

符合规则 2,不需要额外对齐

Part2 内存布局:ecax|bbbb|dddd|dddd

通过对比 Part1 和 Part2 的内存布局,你会发现两者有很大的不同。如下:

仔细一看, Part1 存在许多 Padding。显然它占据了不少空间,那么 Padding 是怎么出现的呢?

通过本文的介绍,可得知是由于不同类型导致需要进行字节对齐,以此保证内存的访问边界

那么也不难理解,为什么 调整结构体内成员变量的字段顺序 就能达到缩小结构体占用大小的疑问了,是因为巧妙地减少了 Padding 的存在。让它们更 “紧凑” 了。这一点对于加深 Go 的内存布局印象和大对象的优化非常有帮

GO语言商业案例(十六):Curve-

Golang 的创建是为了实现最大的用户效率和编码效率。已经熟悉 Java 或 PHP 的程序员可以在几周内接受 Go 的培训(许多人最终会更喜欢它)。在本文中,Dewet Diener 探讨了 Golang 的优缺点,以及它的测试驱动开发 (TDD) 如何完美契合。

Golang 由 Google 开发和设计,于 2009 年作为一种综合性编程语言首次出现,旨在最大限度地提高编码效率。创建该语言的目的是修正其他已建立语言的缺陷。尽管 Golang(或简称为“Go”)是一门年轻的语言,但已经积累了大量的开发人员,因此我们想分享为什么在 Curve 我们喜欢 Golang,以及我们如何采用它来实现我们移动银行业务的目标到云端。

Go 是一种精致的编程语言:它支持“所见即所得”的原则,这意味着清晰易读的代码和更少的复杂抽象。该语言本身易于使用且易于训练。尽管如此,作为一个相对较新的生态系统,要找到对 Go 具有广泛预先知识的工程师可能会很棘手。

然而,与其他编程语言不同,Go 的创建是为了最大限度地提高用户效率。因此,具有 Java 或 PHP 背景的开发人员和工程师可以在几周内获得使用 Go 的技能和培训——根据我们的经验,他们中的许多人最终更喜欢它。

在 Curve,我们大力提倡测试驱动开发 (TDD),Go 的框架与这种方法保持一致。通过简单地命名一个文件 foo_test.go 并在该文件中添加结构化测试函数,Go 将快速有效地运行您的单元测试。这一创新功能提高了生产力,因为它可以更加专注于测试驱动的开发和改进的同行评审机会。

Golang 具有出色的生产优化品质,例如内存占用小,这支持其在大型项目中作为构建块的能力,以及开箱即用的与其他架构的轻松交叉编译。由于 Go 代码被编译为单个静态二进制文件,因此它可以轻松进行容器化,并且通过扩展,将 Go 部署到任何高可用性环境(例如 Kubernetes)中几乎是微不足道的。

它提供了一种机制来保护工作负载,通过拥有非常纤薄的生产容器而没有任何无关的依赖项。这使得构建、部署和维护基于 Go 的资产更加直接和安全,并为希望建立或发展其微服务战略的公司提供了可靠的选择。

Go 是专门为满足我们快速发展的技术生态系统的需求而创建的。例如,Go 可以满足您构建 API 所需的一切,并将其作为其标准库的一部分。它使用简单,高性能的 http 服务器消除了团队设计新项目时经常发生的一些常见的 探索 和设计瘫痪问题——这对于一些其他流行语言(如 Java 和 Node.js)来说太常见了。

Golang 还通过其内置于语言本身的自动格式化程序巧妙地解决了代码格式化分歧。这完全消除了格式争议,进而提高了团队的生产力和注意力。

尽管我是 Go 的拥护者,但它显然也不是没有缺陷。一个争论不休的特性是 Go 没有显式接口,这是许多开发人员习惯的概念。虽然不是有害的,但它可以使选择最适合您的结构的接口成为一项任务。这是因为您不会像在其他流行的编程语言中那样编写 X 实现 Y,但您很快就会接受。

依赖管理也是另一个不属于 Google Golang 开发团队原始设计的功能。开源社区介入并创建了 Glide 和 Dep,最初的努力并没有完全解决问题。从 Go 1.11 开始,添加了对模块的支持,这似乎已成为官方的依赖管理工具。这些挑战并没有削弱 Go 作为一种高效编程语言的独创性,并且它继续为我们提供优于其他编程语言的显着优势。

Golang 吸引了全球敏锐的开发人员的注意,并且围绕它的兴奋继续增长。开源社区因有趣的项目而蓬勃发展;最著名的是 Docker 和 Kubernetes。

正是这种新鲜、有创意但又简单的包装吸引了我们去Go:它是一种令人兴奋的编码语言,可以帮助我们在 Curve 中快速开发以构建更好的产品。


分享标题:怎么优化go语言内存占用 go语言内存不断升高
文章路径:http://myzitong.com/article/ddsdiip.html