Выделено много памяти в Go. Как исправить? - PullRequest
0 голосов
/ 10 июня 2019

Несколько сотен МБ памяти выделено на 50 запросов по 5 МБ.Память выделена и больше не освобождается.Как я могу очистить мою память?Почему это может произойти?

Я пробовал Ubuntu на моем домашнем компьютере и на VPS

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

func main() {
    fmt.Println("start")

    for i := 0; i < 50; i++ {
        go func() {
            DoRequest()
        }()
        time.Sleep(10 * time.Millisecond)
    }

    time.Sleep(10 * time.Minute)
}

func DoRequest() error {
    requestUrl := "https://blockchain.info/rawblock/0000000000000000000eebedea046425bd54626e6c56eb032e66e714d0141ea6"

    req, err := http.NewRequest("GET", requestUrl, nil)

    if err != nil {
        return err
    }

    req.Header.Set("user-agent", "free")

    httpClient := &http.Client{
        Timeout: time.Second * 10,
    }

    resp, err := httpClient.Do(req)

    if resp != nil {
        defer resp.Body.Close()
    }

    if err != nil {
        return err
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    fmt.Println("bodylen", len(body))

    return nil
}

Выделено где-то 400 МБ

Ответы [ 2 ]

7 голосов
/ 10 июня 2019

Вы создаете http-клиент для каждой подпрограммы.

Http-клиент предназначен для создания один раз и много раз.Они обычные безопасные.Они позволяют повторно использовать соединение и другие средства экономии эффективности.

Создайте http-клиент один раз в главном (а не в вашей обычной программе), а затем передайте эту единственную ссылку всем вашим 50 стандартным программам.


Редактировать: Кроме того, хотя это может не иметь практического значения в вашем случае, порядок запроса обычно выглядит так:

resp, err := httpClient.Do(req)
if err != nil {
        return err // check error first
}
defer resp.Body.Close() // no error - so resp will *NOT* be nil - so this is safe

Редактировать 2: Как упомянул @Adrian: сборка мусора go не происходит мгновенно - и не должно быть - так как это дорогостоящая операция.Если вам больше не нужен блок памяти - просто больше не ссылайтесь на него.Пусть GC сделает свою работу, чтобы вы могли сосредоточиться на своей!

Если вам интересно узнать об эволюции GC go:

0 голосов
/ 10 июня 2019
 for i := 0; i < 50; i++ {
        go func() {
            DoRequest()
        }()
        time.Sleep(10 * time.Millisecond)
    }

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

Простым решением является контроль количества подпрограмм, которые могут порождаться (или выполняться) одновременно..

Вы можете предварительно рассчитать занятость памяти в худшем случае, умножив максимальное число подпрограмм, которые вы хотите запускать за раз, и max-memory можно использовать одной подпрограммой.

Вы можете управлять экземплярами подпрограмм с помощью каналов.

Обратитесь к первому ответу на этот вопрос stackoverflow Всегда иметь x число выполняющихся процедур в любомвремя

Всегда используйте сбалансированное решение между производительностью и требуемыми ресурсами.


Обновление от июня 11,2019

ЗдесьЭто пример программы go https://play.golang.org/p/HovNRgp6FxH

...