为了账号安全,请及时绑定邮箱和手机立即绑定

Go 能否在页面级别使用内存?

Go 能否在页面级别使用内存?

Go
繁星点点滴滴 2022-09-12 16:47:22
我是一名Go开发人员,正在阅读一本名为《数据库内部结构》的书。作者广泛讨论了在非常低的级别(特别是在页面级别)使用内存。当我尝试构建自己的数据库时,我浏览了Go文档和其他文章,以获取有关在此级别上使用内存的讨论,但是似乎没有任何内容讨论如何处理特定内存页面中的数据。我的问题是:可以去吗?如果Go不能做到这一点,这是C或C++可以做的事情吗?如果Go,C或C++都无法做到这一点,也许我不明白作者在页面级别使用内存是什么意思,我应该如何思考它?如有必要,请让我知道需要添加到问题中的任何进一步细节。本书摘录上下文是我们正在谈论实现B树和在页面中分组节点。这可以在第 2 章标题为“磁盘结构”的一节中找到。PAGED 二叉树 通过将节点分组到页面中来布置二叉树,如图 2-6 所示,改善了局部性的情况。要查找下一个节点,只需在已提取的页面中跟随指针即可。但是,节点和它们之间的指针仍然会产生一些开销。将结构布置在磁盘上并进一步维护是非平凡的工作,特别是如果键和值没有按随机顺序预先排序和添加。平衡需要页面重组,这反过来又会导致指针更新。它还提供了以下图像:
查看完整描述

2 回答

?
慕婉清6462132

TA贡献1804条经验 获得超2个赞

这本书正在谈论“磁盘结构”。在此上下文中,页面仅表示数据块。磁盘访问在扇区或集群中工作,因此应针对局部性优化数据,以便尽可能地适应这些块。数据库文件设计的挑战是将数据的时间局部性转换为空间局部性。


但这个概念也适用于RAM。在用户空间虚拟内存中的页面级别工作仅意味着了解底层内存体系结构并对其进行优化。


在 x86 上,用户空间虚拟内存以 4 KB* 的页为单位进行组织。


这意味着,在处理大量数据时,使用内存区域是值得的,内存区域是 4 KB 的倍数,与 4 KB 对齐。


在C中,有很多方法可以实现这一目标,例如.aligned_alloc


但是Go走得更远 - 它已经至少在页面大小(在Mac,BSD,Linux和Windows上)对齐了大型数组。


func main() {

    buf := make([]byte, 1024*1024)

    fmt.Printf("%p\n", unsafe.Pointer(&buf[0]))

}

将打印如下内容:


0xc000180000

如果您遇到不这样做的实现,您始终可以“手动”对齐切片,方法是分配PageSize-1额外的字节,然后跳过开头的字节,这些字节不是从PageSize的倍数开始的,使用对齐公式:byte


偏移量 = (对齐 - 基数) & (对齐 - 1)


func main() {

    buf := make([]byte, 1024*1024 + 4096 - 1)

    base := unsafe.Pointer(&buf[0])

    offset := (4096 - uintptr(base)) & (4096 - 1)

    aligned := buf[offset:]

    fmt.Printf("base   : %p\n", unsafe.Pointer(&buf[0]))

    fmt.Printf("aligned: %p\n", unsafe.Pointer(&aligned[0]))

}

(想不出上面会打印不同值的平台)


* 某些平台支持 2MB 和 1GB 页面的大页面。Go 会在可用时自动使用它们。


查看完整回答
反对 回复 2022-09-12
?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

我可能错过了一些东西,但是使用物理内存(与虚拟内存相反)不是语言功能,而是操作系统
的功能。

每个操作系统都提供了使用实际地址空间的方法,这些服务需要提升的权限,并作为驱动程序/内核模块提供,并使用此访问进行内存映射IO或预分配物理内存块(在MMI将其用作分页内存之前)。

我想在系统负载(通过驱动程序)上预先分配内存块并使用它是您希望做的。

如果您打算在“物理内存”上访问“虚拟内存”,我会劝阻您并说这是一个非常微妙和脆弱的机制,除非您发现这样做的巨大优势,否则我看不到任何理由走这条路。


查看完整回答
反对 回复 2022-09-12
  • 2 回答
  • 0 关注
  • 79 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信