类型转换在内部是如何工作的?对于相同的类型转换,内存利用率是多少?

huangapple go评论162阅读模式
英文:

How does type conversion internally work? What is the memory utilization for the same?

问题

Go语言中的类型转换是通过内部机制实现的。类型转换的内存利用情况取决于具体的类型转换操作。例如,在你提供的代码示例中,类型转换的内存利用情况如下:

var str1 string
str1 = "26MB string data"
byt := []byte(str1)
str2 := string(byt)

在这个示例中,str1 是一个字符串变量,占用的内存空间取决于字符串的长度。byt 是将 str1 转换为字节切片的结果,它将占用与 str1 相同的内存空间。str2 是将 byt 转换回字符串的结果,它将占用与 byt 相同的内存空间。

当你进行类型转换时,并不会额外消耗更多的内存,因为类型转换只是改变了变量的类型,而不会改变变量的值或占用的内存空间。

关于你提到的内存不足错误,这可能是由于其他原因导致的,而不是类型转换本身。例如,在你的代码中,当你尝试将字符串转换为字节切片时,如果字符串的长度非常大,可能会导致内存不足。你可以尝试优化你的代码,例如使用流式处理来减少内存占用。

总结起来,类型转换本身不会额外消耗更多的内存,但是在处理大量数据时,需要注意内存的使用情况,以避免出现内存不足的错误。

英文:

How does Go type conversion internally work?

What is the memory utilisation for a type cast?
For example:

var str1 string
str1 = "26MB string data"
byt := []byte(str1)
str2 := string(byt)

whenever I type convert any variable, will it consume more memory?

I am concerned about this because when I try to unmarshall, I get "fatal error: runtime: out of memory"

err = json.Unmarshal([]byte(str1), &obj)

str1 value comes from HTTP response, but read using ioutils.ReadAll, hence it contains the complete response.

答案1

得分: 6

在Go语言中,将一个值转换为另一种类型称为"conversion"(而不是casting),这在规范:Conversions中有详细说明。

> 针对数值类型之间的(非常量)转换或者与字符串类型之间的转换,有特定的规则。这些转换可能会改变x的表示并产生运行时开销。其他所有的转换只改变类型而不改变x的表示。

因此,通常情况下,转换不会创建副本,只是改变类型。但是,转换到/从string类型通常会创建副本,因为string值是不可变的。例如,如果将string转换为[]byte不创建副本,那么通过修改结果字节切片的元素,就可以改变string的内容。

请参考相关问题:https://stackoverflow.com/questions/32253768/does-convertion-between-alias-types-in-go-create-copies/32253871#32253871

在某些情况下(编译器优化),转换到/从string不会创建副本,详细信息请参见https://stackoverflow.com/questions/43470284/golang-bytestring-vs-bytestring/43470344#43470344。

如果你已经将JSON内容作为string值,并且想要进行解组,你不应该将其转换为[]byte,只是为了解组。相反,可以使用strings.NewReader()获取一个从传入的string值读取的io.Reader,并将该读取器传递给json.NewDecoder(),这样你就可以在不复制大型输入JSON字符串的情况下进行解组。

代码示例:

input := "BIG JSON INPUT"
dec := json.NewDecoder(strings.NewReader(input))

var result YourResultType
if err := dec.Decode(&result); err != nil {
    // 处理错误
}

还要注意,如果大型JSON字符串是从io.Reader中读取的,那么这个解决方案可以进一步优化,此时你可以完全省略先读取字符串的步骤,直接将jsonSource传递给json.NewDecoder(),例如:

dec := json.NewDecoder(jsonSource)

var result YourResultType
if err := dec.Decode(&result); err != nil {
    // 处理错误
}
英文:

It's called conversion in Go (not casting), and this is covered in Spec: Conversions:

> Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the representation of x and incur a run-time cost. All other conversions only change the type but not the representation of x.

So generally converting does not make a copy, only changes the type. Converting to / from string usually does, as string values are immutable, and for example if converting a string to []byte would not make a copy, you could change the content of the string by changing elements of the resulting byte slice.

See related question: https://stackoverflow.com/questions/32253768/does-convertion-between-alias-types-in-go-create-copies/32253871#32253871

There are some exceptions (compiler optimizations) when converting to / from string does not make a copy, for details see https://stackoverflow.com/questions/43470284/golang-bytestring-vs-bytestring/43470344#43470344.

If you already have your JSON content as a string value which you want to unmarshal, you should not convert it to []byte just for the sake of unmarshaling. Instead use strings.NewReader() to obtain an io.Reader which reads from the passed string value, and pass this reader to json.NewDecoder(), so you can unmarshal without having to make a copy of your big input JSON string.

This is how it could look like:

input := "BIG JSON INPUT"
dec := json.NewDecoder(strings.NewReader(input))

var result YourResultType
if err := dec.Decode(&result); err != nil {
    // Handle error
}

Also note that this solution can further be optimized if the big JSON string is read from an io.Reader, in which case you can completely omit reading it first, just pass that to json.NewDecoder() directly, e.g.:

dec := json.NewDecoder(jsonSource)

var result YourResultType
if err := dec.Decode(&result); err != nil {
    // Handle error
}

huangapple
  • 本文由 发表于 2017年7月20日 15:19:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/45207920.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定