преобразовать byte[] в строку в golang странно занять кучу

Я обнаружил странную занятую кучу при преобразовании byte[] в строку с кодом ниже

package main

import (
  "bytes"
  "fmt"
  "net/http"
  _ "net/http/pprof"
  "strings"
  "time"
)

var (
  c = make(chan int, 500000)
)

func main() {
  go func() {
    http.ListenAndServe(":8080", nil)
  }()
  f := func(ss []string) {
    fmt.Println(ss)
    time.Sleep(time.Millisecond)
    <-c
  }
  for {
    c <- 1
    bs := bytes.NewBufferString("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z").Bytes()
    fmt.Println(bs) // will raise memory leak after marked as comment???
    s := string(bs)
    ss := strings.Split(s, ",")
    go f(ss)
  }
}
  1. без fmt.Println(bs) память будет постепенно исчерпываться.

  2. с fmt.Println(bs) работает нормально. не могу понять что случилось? я работаю с version go1.9.2 darwin/amd64


person Nelson    schedule 03.12.2017    source источник


Ответы (1)


Нет, утечки памяти нет:
Вы используете 500000 одновременных горутин, вам просто нужно ограничить (уменьшить) количество одновременных горутин. сильный>, например:

c := make(chan int, runtime.NumCPU())

Попробуйте это (и посмотрите конец этого редактирования):

package main

import (
    "bytes"
    "fmt"
    "runtime"
    "strings"
    "time"
)

func main() {
    c := make(chan int, runtime.NumCPU())
    for {
        c <- 1
        bs := bytes.NewBufferString("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z").Bytes()
        s := string(bs)
        ss := strings.Split(s, ",")
        go func(ss []string) {
            fmt.Println(ss)
            time.Sleep(time.Millisecond)
            <-c
        }(ss)
    }
}

Ваш код:

package main

import (
    "bytes"
    "fmt"
    "net/http"
    _ "net/http/pprof"
    "strings"
    "time"
)

var (
    c = make(chan int, 500000)
)

func main() {
    go func() {
        http.ListenAndServe(":8080", nil)
    }()
    f := func(ss []string) {
        fmt.Println(ss)
        time.Sleep(time.Millisecond)
        <-c
    }
    for {
        c <- 1
        bs := bytes.NewBufferString("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z").Bytes()
        // fmt.Println(bs) // will raise memory leak after marked as comment???
        s := string(bs)
        ss := strings.Split(s, ",")
        go f(ss)
    }
}

Через некоторое время он достигает устойчивого состояния и даже уменьшает использование памяти:

// Mem          CPU time:
// 5,464,208K 0:1:20
// 5,468,208K 0:2:20
// 5,469,608K 0:3:20
// 5,469,844K 0:4:20
// 5,469,844K 0:5:20
// 5,469,848K 0:6:20
// 5,469,848K 0:7:20 fixed
// 5,469,848K 0:8:20 fixed
// 5,469,616K 0:9:20 reduced
person wasmup    schedule 03.12.2017
comment
Вы пытались добавить fmt.Println (bs)? это уменьшит занимаемую память - person Nelson; 03.12.2017
comment
Да, конечно. Использование fmt.Println(bs) дает GC (сборщику мусора) больше времени для сбора памяти, а использование памяти составляет 25520KBytes для меня с fmt.Println(bs) . - person wasmup; 03.12.2017
comment
Да, fmt.Println(bs) делает GC больше раз. Но никакая печать не должна занимать все больше и больше памяти до предела системы. - person Nelson; 03.12.2017
comment
В моем тестировании ни один отпечаток не будет занимать более 3 ГБ памяти. - person Nelson; 03.12.2017
comment
Я до сих пор не могу понять, почему без печати не будет занимать системную память, а с печатью работает нормально. Никакая печать не должна периодически запускать GC? - person Nelson; 03.12.2017
comment
см. планировщик Go и это - person wasmup; 03.12.2017