如何高效优化Go中cipher.AEAD.Seal()的内存使用

Go编程,cipher.AEAD.Seal(),内存优化,ChaCha20-Poly1305,Golang加密算法

GoLang cipher.AEAD.Seal()

在使用Go语言中的ChaCha20-Poly1305实现进行数据加密时,有时会发现内存使用量比预期要高。这是因为Go语言的AEAD(Authenticated Encryption with Associated Data)密码实现的方式要求我们将整个数据保存在内存中以创建哈希值,而不仅仅是明文大小。

示例

下面是一个简单的例子程序,加密4 GiB的数据:

package main
import (
"fmt"
"os"
"runtime"
"golang.org/x/crypto/chacha20poly1305"
)
func main() {
showMemUsage("START")
plaintext := make([]byte, 4*1024*1024*1024) // 4 GiB
showMemUsage("STAGE 1")
key := make([]byte, chacha20poly1305.KeySize)
if cipher, err := chacha20poly1305.New(key); err == nil {
showMemUsage("STAGE 2")
nonce := make([]byte, chacha20poly1305.NonceSize)
cipher.Seal(plaintext[:0], nonce, plaintext, nil)
}
showMemUsage("END")
}
func showMemUsage(tag string) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Fprintf(os.Stdout, "[%s] Alloc = %v MiB, TotalAlloc = %v MiB\n", tag, m.Alloc/1024/1024, m.TotalAlloc/1024/1024)
}

根据源代码注释,我们可以使用`plaintext[:0]`作为目标切片来重用明文的存储空间。然而,在这个例子中,无论我们如何尝试重用内存,程序总是使用了8 GiB的内存来加密4 GiB的数据。

[START] Alloc = 0 MiB, TotalAlloc = 0 MiB
[STAGE 1] Alloc = 4096 MiB, TotalAlloc = 4096 MiB
[STAGE 2] Alloc = 4096 MiB, TotalAlloc = 4096 MiB
[END] Alloc = 8192 MiB, TotalAlloc = 8192 MiB

为什么会出现这种情况?

ChaCha20-Poly1305密码的工作原理

ChaCha20-Poly1305是一个AEAD密码,它将明文与随机生成的nonce结合起来,并使用密钥进行加密。同时,它还会生成一个16字节的认证标签(authentication tag),附加到密文的末尾。在解密时,我们需要验证认证标签以确保密文的完整性和真实性。

解析代码

根据源代码注释和问题中提到的话题,我们可以看出问题可能出在切片的容量上。根据Go语言的规范,切片的长度可以小于或等于其容量,但不能超过容量。

  1. 首先创建了一个大小为4 GiB的明文切片`plaintext`。然后,我们生成了一个密钥`key`并使用它初始化了一个ChaCha20-Poly1305密码实例`cipher`。

  2. 我们生成了一个随机的nonce,并调用`cipher.Seal()`方法来对明文进行加密。

  3. 问题中提到的疑惑在于,即使我们尝试重用在cipher.AEAD.Seal()方法中,参数dst被用于存储加密后的数据,而参数plaintext作为输入明文数据。根据源代码注释,如果我们希望重用明文的存储空间用于加密输出,我们应该使用`plaintext[:0]`作为dst参数。这样做将确保加密后的数据直接写入到原始明文切片中,并避免额外的内存分配。

  4. 在我们的示例程序中,无论我们如何尝试重用`plaintext[:0]`作为dst参数,程序都会占用8 GiB的内存来加密4 GiB的数据。这是因为Go语言的cipher.AEAD.Seal()方法在进行加密操作时,会为密文数据分配一个新的切片并返回。虽然我们使用了`plaintext[:0]`作为dst参数,但实际上它不会改变分配的内存量。

那么有没有办法减少内存占用呢? 

答案是:有的。我们可以通过手动创建一个长度已知且足够容纳密文的切片,然后将其传递给cipher.AEAD.Seal()方法。这样做可以避免cipher.AEAD.Seal()方法中的额外内存分配。

下面是修改后的示例代码:

package main
import (
"fmt"
"os"
"runtime"
"golang.org/x/crypto/chacha20poly1305"
)
func main() {
showMemUsage("START")
plaintext := make([]byte, 4*1024*1024*1024) // 4 GiB
showMemUsage("STAGE 1")
key := make([]byte, chacha20poly1305.KeySize)
if cipher, err := chacha20poly1305.New(key); err == nil {
showMemUsage("STAGE 2")
nonce := make([]byte, chacha20poly1305.NonceSize)
ciphertext := make([]byte, len(plaintext)+cipher.Overhead())
cipher.Seal(ciphertext[:0], nonce, plaintext, nil)
}
showMemUsage("END")
}
func showMemUsage(tag string) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Fprintf(os.Stdout, "[%s] Alloc = %v MiB, TotalAlloc = %v MiB\n", tag, m.Alloc/1024/1024, m.TotalAlloc/1024/1024)
}

在修改后的代码中,我们首先创建了一个足够容纳密文的切片`ciphertext`,并且长度已知为明文切片`plaintext`的长度加上密码算法的Overhead(即认证标签的大小)。然后,我们将`ciphertext[:0]`作为dst参数传递给cipher.AEAD.Seal()方法,以确保加密后的数据直接写入到原始切片中。

通过这种方式,我们可以减少内存占用并提高性能。运行修改后的示例程序,你会发现内存使用量与明文大小相匹配:

[START] Alloc = 0 MiB, TotalAlloc = 0 MiB
[STAGE 1] Alloc = 4096 MiB, TotalAlloc = 4096 MiB
[STAGE 2] Alloc = 4096 MiB, TotalAlloc = 8192 MiB
[END] Alloc = 8192 MiB, TotalAlloc = 8192 MiB

现在,程序只使用了与明文大小相匹配的内存(4 GiB),而不再占用8 GiB的内存。这是因为我们手动创建了一个足够容纳密文的切片,并将其传递给cipher.AEAD.Seal()方法,避免了额外的内存分配。

通过优化cipher.AEAD.Seal()方法的内存使用,我们可以提高加密性能并减少内存消耗,从而更好地满足应用程序的需求。文章来源地址https://www.toymoban.com/diary/golang/662.html

到此这篇关于如何高效优化Go中cipher.AEAD.Seal()的内存使用的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.toymoban.com/diary/golang/662.html

如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用
如何使用 Docker Buildx 顺序构建多架构镜像
上一篇 2024年01月03日 01:29
在K8S上部署使用NATS消息传递的Go应用程序
下一篇 2024年01月03日 02:18

相关文章

  • 掌握 Spring Boot 运行内存及内存参数设置:助力高效应用部署与优化

    pring Boot 是当今非常流行的 Java 应用框架之一,在企业级应用开发中被广泛使用。应用部署和优化是企业级应用开发的一个非常重要的方面。在这篇博客中,我们将学习如何掌握 Spring Boot 运行内存及内存参数设置,从而助力高效的应用部署和优化。 Java 应用程序通过 Java 虚拟

    2024年01月21日
    浏览(26)
  • pandas DataFrame内存优化技巧:让数据处理更高效

    Pandas 无疑是我们数据分析时一个不可或缺的工具,它以其强大的数据处理能力、灵活的数据结构以及易于上手的API赢得了广大数据分析师和机器学习工程师的喜爱。 然而,随着数据量的不断增长,如何高效、合理地管理内存,确保 Pandas DataFrame 在运行时不会因内存不足而崩

    2024年03月14日
    浏览(22)
  • 使用秘籍|如何实现图数据库 NebulaGraph 的高效建模、快速导入、性能优化

    本文整理自 NebulaGraph PD 方扬在「NebulaGraph x KubeBlocks」meetup 上的演讲,主要包括以下内容: NebulaGraph 3.x 发展历程 NebulaGraph 最佳实践 建模篇 导入篇 查询篇 NebulaGraph 自 2019 年 5 月开源发布第一个 alpha 版本以来,陆陆续续发布了 2.0 GA,到现在 v3.6.0,已经是 v3.x 版本中比较后期

    2024年02月10日
    浏览(22)
  • 【C语言进阶】智能管理:如何使用柔性数组实现内存优化

    目录 一、定义 二、用法 三、特点 四、注意事项 五、总结 在 C 语言中,柔性数组(Flexible Array)是一种特殊类型的数组,它允许程序员在运行时动态地分配数组的大小,从而实现更灵活的内存管理。本文将详细介绍柔性数组的定义、用法、特点及注意事项。 C 语言的数组是

    2023年04月24日
    浏览(30)
  • DS/ML:模型全流程优化之系统优化—替代Pandas库的大数据高效处理技术优化集合如HDF5技术(压缩文件)+vaex库(内存映射)+dask库(集群技术)替代pandas的各自骚操作实现代码

    DS/ML:模型全流程优化之系统优化—替代Pandas库的大数据高效处理技术优化集合如HDF5技术(压缩文件)+vaex库(内存映射)+dask库(集群技术)替代pandas的各自骚操作实现代码 目录

    2024年02月09日
    浏览(18)
  • redis如何优化内存

    string转hash存 对key拆分,成hash,注意:每个hash key下的filed-value个数不能超过限定值,否则不会走ziplist存储;因此可以进行hash算法来分配hash桶,控制每个桶的原数个数;或者取数字key 的后三位,控制每个hash只有999个元素。 key 由string转数字 问题: 较小的概率发生hash冲突,

    2024年02月10日
    浏览(17)
  • go基础07-了解map实现原理并高效使用

    对于C程序员出身的Gopher来说,map类型是和切片、interface一样能让他们感受到Go语言先进性的重要语法元素。map类型也是Go语言中最常用的数据类型之一。 一些有关Go语言的中文教程或译本将map称为字典或哈希表,但在这里我选择不译,直接使用map。map是Go语言提供的一种抽象数

    2024年02月09日
    浏览(24)
  • 小白学go基础06-了解切片实现原理并高效使用

    slice,中文多译为切片,是Go语言在数组之上提供的一个重要的抽象数据类型。在Go语言中,对于绝大多数需要使用数组的场合,切片实现了完美替代。并且和数组相比,切片提供了更灵活、更高效的数据序列访问接口。 在对切片一探究竟之前,我们先来简单了解一下Go语言中

    2024年02月09日
    浏览(16)
  • MySQL中如何高效的实现模糊查询(附30条优化建议)

    在使用msyql进行模糊查询的时候,很自然的会用到like语句,通常情况下,在数据量小的时候,不容易看出查询的效率,但在数据量达到百万级,千万级的时候,查询的效率就很容易显现出来。这个时候查询的效率就显得很重要! 一般情况下like模糊查询的写法为(field已建立索

    2024年01月22日
    浏览(21)
  • 内存不够大?python如何对内存进行优化

    对于C语言来说,内存泄露是个很常见的事故,因此写代码的时候要格外注意 无用内存的释放 ,但是对于pythoner来说,一般都不会关心这些,因为python会自己去管理内存。 但是最近我遇到一个问题,我在写一个程序,将会占用很大的内存,我先使用了一个集合用来存储数据。

    2024年02月05日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包