Skip to content

Commit

Permalink
Merge pull request #710 from devlights:add-heapalloc-with-clone-method
Browse files Browse the repository at this point in the history
Add using strings.Clone() example
  • Loading branch information
devlights authored Dec 5, 2023
2 parents 5d0597b + 04afd88 commit 53f9560
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/singleapp/using_clone_method/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
app
38 changes: 38 additions & 0 deletions examples/singleapp/using_clone_method/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# これは何?

Go 1.18 で追加された ```strings.Clone()``` を利用したサンプルです。

内部で大きな文字列を確保している状態で、それらの部分文字列を別の場所に確保する処理を実施しています。

現状(2023-12-05 現在)のGoの標準コンパイラでは、元の文字列と部分文字列は同じメモリデータを共有するので

部分文字列をシャローコピーして別のストアに保持したままだと、メモリが開放されません。

```strings.Clone()``` を利用することにより、ディープコピーが行われるので、メモリが開放されるようになります。

## 実行例

```sh
$ task
task: [build] go build -o app main.go
task: [run-not-use-clone] ./app
Title HeapAlloc HeapObjects
[start ] 192792 144
[gen ] 11482528 4576
[store ] 11487008 4588
[checkpoint] 8471296 1363
[checkpoint] 8475728 1372
[checkpoint] 8475728 1372
[checkpoint] 8475728 1372
[checkpoint] 8475736 1373
task: [run-use-clone] ./app -use
Title HeapAlloc HeapObjects
[start ] 192824 144
[gen ] 11497632 4607
[store ] 11507440 4952
[checkpoint] 296112 724
[checkpoint] 300536 732
[checkpoint] 300536 732
[checkpoint] 300544 733
[checkpoint] 300544 733
```
19 changes: 19 additions & 0 deletions examples/singleapp/using_clone_method/Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# https://taskfile.dev

version: '3'

tasks:
default:
deps: [ build ]
cmds:
- task: run-not-use-clone
- task: run-use-clone
build:
cmds:
- go build -o app main.go
run-not-use-clone:
cmds:
- ./app
run-use-clone:
cmds:
- ./app -use
108 changes: 108 additions & 0 deletions examples/singleapp/using_clone_method/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package main

import (
"flag"
"io"
"log"
"os/exec"
"runtime"
"strings"
"unsafe"
)

const (
NUM_ITEMS = 1000
SHELL = "/bin/bash"
)

var (
store = make([]string, NUM_ITEMS)
)

func init() {
log.SetFlags(0)
}

func mem(prefix string) {
var (
m = runtime.MemStats{}
)

runtime.ReadMemStats(&m)
log.Printf("[%s]\t%8d\t%8d\n", prefix, m.HeapAlloc, m.HeapObjects)
}

func gen() []string {
var (
l = make([]string, NUM_ITEMS)
)

for i := 0; i < NUM_ITEMS; i++ {
output, _ := exec.Command(SHELL, "-c", "openssl rand -base64 4096 | tr -d '\n'").Output()
l[i] = unsafe.String(&output[0], len(output))
}

return l
}

func main() {
log.Println("Title \tHeapAlloc\tHeapObjects")
mem("start ")

var (
use = flag.Bool("use", false, "Use strings.Clone()")
)
flag.Parse()

var (
l = gen()
)
mem("gen ")

for i := 0; i < NUM_ITEMS; i++ {
storeValue := l[i][:5]

if *use {
store[i] = strings.Clone(storeValue)
} else {
store[i] = storeValue
}
}
mem("store ")

runtime.GC()

for i, v := range store {
if i%200 == 0 {
runtime.GC()
mem("checkpoint")
}

io.Discard.Write(unsafe.Slice(unsafe.StringData(v), len(v)))
}

/*
$ task
task: [build] go build -o app main.go
task: [run-not-use-clone] ./app
Title HeapAlloc HeapObjects
[start ] 192792 144
[gen ] 11482528 4576
[store ] 11487008 4588
[checkpoint] 8471296 1363
[checkpoint] 8475728 1372
[checkpoint] 8475728 1372
[checkpoint] 8475728 1372
[checkpoint] 8475736 1373
task: [run-use-clone] ./app -use
Title HeapAlloc HeapObjects
[start ] 192824 144
[gen ] 11497632 4607
[store ] 11507440 4952
[checkpoint] 296112 724
[checkpoint] 300536 732
[checkpoint] 300536 732
[checkpoint] 300544 733
[checkpoint] 300544 733
*/
}

0 comments on commit 53f9560

Please sign in to comment.