我向你们中的Go程序员提问。我找不到有关Go内存模型细节的信息。我将尝试描述我的问题:
如果我在C中声明并定义一个变量或数组,我知道它存在于RAM的某个位置,只有一个特定的地址,直到我做了一些会改变它的东西。
Python中并非如此:Python为我完成了整个内存管理,我不能确定我的数据总是位于一个位置。例如。字符串在实践中是不可变的,即使语言表明它们不是。这使得使用敏感数据进行安全编程几乎不可能(或者至少非常不切实际)。
我的问题是:Go如何从这个角度出发。它更像是C还是像Python一样?还是完全不同?是否可以像在C中那样舒适地处理敏感数据?
答案 0 :(得分:6)
注意:如“Go Slices: usage and internals”中所述:
[4]int
的内存中表示只是顺序排列的四个整数值:
Go的数组是值。
数组变量表示整个数组; 它不是指向第一个数组元素的指针(如C中的情况)。这意味着当您分配或传递数组值时,您将复制其内容 (为了避免复制,你可以传递指向数组的指针,但那是指向数组的指针,而不是数组。)
考虑数组的一种方法是作为一种结构但使用索引而不是命名字段:固定大小的复合值。
如果您正在查看“指向数组的指针”,那么您需要一个切片。
切片是数组段的描述符。它由指向数组的指针,段的长度及其容量(段的最大长度)组成。
我们之前由
s
创建的变量make([]byte, 5)
的结构如下:
对于数组和切片的内存分配方式,您可以查看“Effective Go”
Go有两个分配原语,内置函数
new
和make
他们做不同的事情并适用于不同的类型,这可能令人困惑,但规则很简单。
让我们来谈谈新的第一个。它是一个内置函数,可以分配内存,但与其他语言中的名称不同,它不会初始化内存,只会将内存归零。
也就是说,new(T)
为类型为T
的新项目分配归零存储并返回其地址,类型为*T
。
在Go术语中,它返回一个指向新分配的类型为T
的零值的指针。allocation with
make
:内置函数make(T, args)
的用途与new(T)
不同。它仅创建切片,贴图和通道,并返回类型T
(不是*T
)的初始化(非归零)值。
区别的原因是这三种类型在覆盖范围内表示对使用前必须初始化的数据结构的引用。
例如,切片是一个三项描述符,包含指向数据的指针(在数组内),长度和容量,并且在初始化这些项之前,切片为零。
点击“Understanding Pointers and Memory Allocation”了解更多信息。
答案 1 :(得分:2)
在Go中处理内存的方式介于它在C中的工作方式以及它在Python中的工作方式。 Go提供了比Python更多的内存布局控制 - 大约和C一样多。但Go像垃圾一样被垃圾收集。因此,您无法明确控制内存的分配和释放。
有时Go中的内存可以自动移动。当goroutine的堆栈变满时,它会被复制到更大的堆栈中。有一天Go可能会有像Java一样的复制垃圾收集器。 (现在不行。)
因此,确保敏感数据不会留在内存中可能比在C中更难。但在具有虚拟内存的系统(即所有现代计算机)中,总是有可能交换您的进程out和其他一些进程将得到它的记忆。也许操作系统首先将内存归零,也许它不会。
但是在Go中,将敏感值留在内存中并不像在C中那样危险.Go不会让你访问C之外的内存,就像C对其数组一样。 (这就是导致Heartbleed错误的原因。)当你在Go中分配一大块内存时,它被归零,所以没有任何东西可以泄漏。