0

0

Go语言uint64:固定内存与变长序列化深度解析

心靈之曲

心靈之曲

发布时间:2025-10-18 09:17:06

|

732人浏览过

|

来源于php中文网

原创

Go语言uint64:固定内存与变长序列化深度解析

本文深入探讨go语言中uint64类型的存储机制。在内存中,uint64始终占用8字节的固定空间。然而,在进行序列化时,如使用binary.putuvarint函数,uint64可能会被编码为可变长度的字节序列,最多可达10字节。文章将详细解释这两种情况的差异及其背后的设计原理,并通过示例代码加深理解,帮助开发者区分内存存储与数据编码的概念。

在Go语言的开发实践中,理解基本数据类型的内存占用和序列化行为至关重要。特别是对于uint64这样的整数类型,其在内存中的表现与在数据传输或存储时的编码方式可能存在显著差异。

1. uint64的内存占用:固定8字节

根据Go语言官方规范,uint64被定义为一个无符号的64位整数。这意味着无论其存储的数值大小如何(从0到2^64-1),它在内存中都将占用固定的8个字节(即64位)。Go语言对基本数据类型的大小和对齐有明确的保证。

以下是Go语言中部分基本数据类型的内存大小概览:

类型 内存大小 (字节)
byte, uint8, int8 1
uint16, int16 2
uint32, int32, float32 4
uint64, int64, float64, complex64 8
complex128 16

从上表可以看出,uint64明确被指定为占用8个字节。这个规则在程序运行时是严格遵守的,它保证了内存访问的效率和确定性。

立即学习go语言免费学习笔记(深入)”;

2. binary.PutUvarint的变长编码:最多10字节

尽管uint64在内存中固定占用8字节,但在进行数据序列化时,例如使用encoding/binary包中的PutUvarint函数,其编码后的字节数可能会有所不同。PutUvarint实现了变长编码(varint),旨在用更少的字节表示较小的数字,从而节省存储或传输带宽。

PutUvarint函数可以将一个uint64值编码为最多10个字节的序列。这种看似矛盾的现象,源于变长编码的设计原理:

  • 变长编码机制: Varint编码通过每个字节的最高位(MSB,Most Significant Bit)来指示当前字节是否是数字的最后一个字节。如果MSB为1,表示后续还有字节;如果MSB为0,则表示这是数字的最后一个字节。每个字节的低7位用于存储实际的数值。

  • uint64的特殊性: 对于uint64,其最大值需要64位来表示。如果完全按照上述7位数据位+1位控制位的规则,理论上需要ceil(64/7) = 10个字节。具体来说,前9个字节的MSB都为1,各自携带7位数据;最后一个字节的MSB为0,携带剩余的位。

    小蓝本
    小蓝本

    ToB智能销售增长平台

    下载
  • Go语言库的设计考量: Go语言的encoding/binary库在实现PutUvarint时,确实考虑到了这种最长10字节的情况。其设计注释中提到:

    Design note:
    // At most 10 bytes are needed for 64-bit values. The encoding could
    // be more dense: a full 64-bit value needs an extra byte just to hold bit 63.
    // Instead, the msb of the previous byte could be used to hold bit 63 since we
    // know there can't be more than 64 bits. This is a trivial improvement and
    // would reduce the maximum encoding length to 9 bytes. However, it breaks the
    // invariant that the msb is always the "continuation bit" and thus makes the
    // format incompatible with a varint encoding for larger numbers (say 128-bit).

    这段注释解释了为什么是10字节而不是9字节:为了保持MSB作为“延续位”的通用不变性,即使对于64位值,也可能需要额外的字节来存储最高位。如果为了将最大长度减少到9字节而改变MSB的含义,将会破坏varint编码的通用性,使其无法兼容更大位数(如128位)的数字。因此,为了设计上的简洁性和可扩展性,Go选择了最多10字节的方案。

示例代码:PutUvarint的编码长度

以下Go语言代码示例展示了不同uint64值经过PutUvarint编码后的字节长度:

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    // binary.MaxVarintLen64 定义了 uint64 变长编码的最大字节数,即 10
    buf := make([]byte, binary.MaxVarintLen64)

    // 较小的 uint64 值
    val1 := uint64(150) // 150 (十进制) = 10010110 (二进制)
    n1 := binary.PutUvarint(buf, val1)
    fmt.Printf("值: %d, 编码字节: %v, 长度: %d\n", val1, buf[:n1], n1)
    // 预期输出: 150 编码为 2 字节

    // 刚好需要 1 字节表示的最大值 (0-127)
    val2 := uint64(127) // 01111111
    n2 := binary.PutUvarint(buf, val2)
    fmt.Printf("值: %d, 编码字节: %v, 长度: %d\n", val2, buf[:n2], n2)
    // 预期输出: 127 编码为 1 字节

    // 较大的 uint64 值,需要 9 字节
    // 1 << 56 刚好跨越到第 9 个 7 位组
    val3 := uint64(1 << 56) // 1后面跟56个0
    n3 := binary.PutUvarint(buf, val3)
    fmt.Printf("值: %d, 编码字节: %v, 长度: %d\n", val3, buf[:n3], n3)
    // 预期输出: 1<<56 编码为 9 字节

    // 最大的 uint64 值 (2^64 - 1),需要 10 字节
    val4 := uint64(0xFFFFFFFFFFFFFFFF) // 所有位都是 1
    n4 := binary.PutUvarint(buf, val4)
    fmt.Printf("值: %d, 编码字节: %v, 长度: %d\n", val4, buf[:n4], n4)
    // 预期输出: 最大 uint64 值编码为 10 字节
}

运行上述代码,您会观察到不同大小的uint64值,其通过PutUvarint编码后的字节长度确实是可变的,从1字节到10字节不等。

3. 内存存储与序列化编码的区别及注意事项

理解uint64在内存中的固定8字节占用与序列化时变长编码之间的差异至关重要。

  • 内存存储 (In-Memory Storage): 当您在Go程序中声明一个uint64变量时,它会直接在内存中分配8个字节的空间。这是CPU处理数据的基础,保证了数据访问的效率和一致性。例如,数组或结构体中的uint64字段都会占用固定大小。
  • 序列化编码 (Serialization Encoding): 当您需要将uint64数据持久化到文件、传输到网络或存储到数据库时,通常会进行序列化。binary.PutUvarint就是一种序列化方式,它以空间效率为主要目标,通过变长编码来减少实际存储或传输的字节数。其他序列化格式(如JSON、Protocol Buffers、Gob等)也可能有自己的编码规则。

注意事项:

  1. 区分场景: 在分析程序性能和内存使用时,应关注内存中的实际占用(固定8字节)。在设计数据传输协议或文件格式时,则需要考虑序列化编码的效率和兼容性。
  2. 选择合适的编码: 如果对数据长度有严格的固定要求(例如,网络协议中必须是固定长度的字段),则不应使用变长编码,而应使用binary.PutUint64等固定长度的编码函数。
  3. 兼容性: 使用PutUvarint编码的数据,必须使用binary.Uvarint来解码,以确保正确解析。
  4. 性能考量: 变长编码在节省空间的同时,可能会引入额外的编码/解码计算开销。对于极度性能敏感的场景,需要权衡空间效率与编解码速度。

总结

Go语言中的uint64类型在内存中始终占用8个字节,这是其在程序运行时固定且高效的存储方式。然而,当数据需要进行序列化以供存储或传输时,binary.PutUvarint等变长编码方法可以根据数值大小,将其编码为1到10个字节的序列。这种差异是内存管理和数据传输优化之间的权衡结果。开发者应清晰理解这两种情况,并根据具体应用场景选择最合适的处理方式。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

408

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

532

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

309

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

74

2025.09.10

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

299

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

222

2025.10.31

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

194

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

187

2025.07.04

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

80

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.2万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号