Go에서 슬라이스를 지우는 적절한 방법은 무엇입니까?
다음은 go 포럼 에서 찾은 내용입니다 .
// test.go
package main
import (
"fmt"
)
func main() {
letters := []string{"a", "b", "c", "d"}
fmt.Println(cap(letters))
fmt.Println(len(letters))
// clear the slice
letters = letters[:0]
fmt.Println(cap(letters))
fmt.Println(len(letters))
}
이 올바른지?
명확히하기 위해 버퍼를 지워 재사용 할 수 있습니다.
예는 bytes 패키지의 Buffer.Truncate 함수입니다.
Reset은 Truncate (0) 만 호출합니다. 따라서이 경우 70 행은 다음과 같이 평가됩니다. b.buf = b.buf [0 : 0]
http://golang.org/src/pkg/bytes/buffer.go
// Truncate discards all but the first n unread bytes from the buffer.
60 // It panics if n is negative or greater than the length of the buffer.
61 func (b *Buffer) Truncate(n int) {
62 b.lastRead = opInvalid
63 switch {
64 case n < 0 || n > b.Len():
65 panic("bytes.Buffer: truncation out of range")
66 case n == 0:
67 // Reuse buffer space.
68 b.off = 0
69 }
70 b.buf = b.buf[0 : b.off+n]
71 }
72
73 // Reset resets the buffer so it has no content.
74 // b.Reset() is the same as b.Truncate(0).
75 func (b *Buffer) Reset() { b.Truncate(0) }
답변
그것은 모두 당신의 ‘명확한’정의에 달려 있습니다. 유효한 것 중 하나는 확실히 다음과 같습니다.
slice = slice[:0]
하지만 문제가 있습니다. 슬라이스 요소가 T 유형 인 경우 :
var slice []T
다음 시행 len(slice)
은 “트릭”이상으로, 제로로, 하지 의 요소를 만들
slice[:cap(slice)]
가비지 수집 대상입니다. 이는 일부 시나리오에서 최적의 접근 방식 일 수 있습니다. 그러나 이것은 또한 “메모리 누수”의 원인이 될 수 있습니다. 메모리는 사용되지 않지만 잠재적으로 도달 할 수 있으며 ( ‘슬라이스’재분할 후) 가비지 “수집 가능”이 아닙니다.
답변
슬라이스를 nil
로 설정하는 것이 슬라이스를 지우는 가장 좋은 방법입니다. nil
이동중인 슬라이스는 완벽하게 잘 작동하며 슬라이스를로 설정 nil
하면 기본 메모리가 가비지 수집기에 해제됩니다.
package main
import (
"fmt"
)
func dump(letters []string) {
fmt.Println("letters = ", letters)
fmt.Println(cap(letters))
fmt.Println(len(letters))
for i := range letters {
fmt.Println(i, letters[i])
}
}
func main() {
letters := []string{"a", "b", "c", "d"}
dump(letters)
// clear the slice
letters = nil
dump(letters)
// add stuff back to it
letters = append(letters, "e")
dump(letters)
}
인쇄물
letters = [a b c d]
4
4
0 a
1 b
2 c
3 d
letters = []
0
0
letters = [e]
1
1
0 e
두 슬라이스가 동일한 기본 메모리를 가리 키도록 슬라이스를 쉽게 앨리어싱 할 수 있습니다. 에 대한 설정 nil
은 해당 별칭을 제거합니다.
이 방법은 용량을 0으로 변경합니다.
답변
나는 내 목적을 위해이 문제를 약간 조사하고 있었다. 나는 구조체 조각 (포인터 포함)을 가지고 있었고 제대로 된 것인지 확인하고 싶었다. 이 스레드에 올랐고 결과를 공유하고 싶었습니다.
연습을 위해 약간의 운동장을 사용했습니다 :
https://play.golang.org/p/9i4gPx3lnY
이것에 평가되는 :
package main
import "fmt"
type Blah struct {
babyKitten int
kittenSays *string
}
func main() {
meow := "meow"
Blahs := []Blah{}
fmt.Printf("Blahs: %v\n", Blahs)
Blahs = append(Blahs, Blah{1, &meow})
fmt.Printf("Blahs: %v\n", Blahs)
Blahs = append(Blahs, Blah{2, &meow})
fmt.Printf("Blahs: %v\n", Blahs)
//fmt.Printf("kittenSays: %v\n", *Blahs[0].kittenSays)
Blahs = nil
meow2 := "nyan"
fmt.Printf("Blahs: %v\n", Blahs)
Blahs = append(Blahs, Blah{1, &meow2})
fmt.Printf("Blahs: %v\n", Blahs)
fmt.Printf("kittenSays: %v\n", *Blahs[0].kittenSays)
}
해당 코드를있는 그대로 실행하면 “meow”및 “meow2″변수에 대해 동일한 메모리 주소가 동일한 것으로 표시됩니다.
Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
Blahs: []
Blahs: [{1 0x1030e0f0}]
kittenSays: nyan
나는 구조체가 가비지 수집되었음을 확인한다고 생각합니다. 이상하게도 주석 처리 된 인쇄 줄의 주석을 제거하면 야옹에 대해 다른 메모리 주소가 생성됩니다.
Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
kittenSays: meow
Blahs: []
Blahs: [{1 0x1030e0f8}]
kittenSays: nyan
나는 이것이 어떤 식 으로든 (?) 인쇄가 지연 되었기 때문일 수 있지만, 일부 메모리 관리 동작에 대한 흥미로운 그림과 다음 항목에 대한 투표가 하나 더 있습니다.
[]MyStruct = nil