Утечка памяти - PullRequest
       8

Утечка памяти

0 голосов
/ 29 апреля 2018

UPD: Измененный код, ничего не меняется

У меня утечка памяти в этой функции, но я не знаю, где.

func CheckProxySOCKS(prox string, c chan QR) (err error) {

    //Sending request through proxy
    dialer, _ := proxy.SOCKS5("tcp", prox, nil, proxy.Direct)
    timeout := time.Duration(5 * time.Second)
    httpClient := &http.Client{Timeout: timeout, Transport: &http.Transport{Dial: dialer.Dial}}
    res, err := httpClient.Get("https://api.ipify.org?format=json")

    if err != nil {

        c <- QR{Addr: prox, Res: false}
        return
    }

    _, err = ioutil.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
        return
    }

    c <- QR{Addr: prox, Res: true}
    return
}

Здесь я назвал это

for _, proxy := range splitedProxies {
    go code.CheckProxySOCKS(proxy, respChan)
}

for range splitedProxies {
    r := <-respChan
    if r.Res {
        checkedProxiesArray = append(checkedProxiesArray, r.Addr)
    }
}

После 3-4 циклов я получил более 40 тыс. Операций (я проверяю это runtime.NumGoroutine()). После запуска приложение использовало около 100 Мб после 4 циклов более 1 ГБ

Github репо со всем кодом

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Вы не всегда закрываете соединение, и вы используете новый клиент и Транспортируйте каждый запрос. Если вы отбрасываете транспорт, вы отбрасываете все соединения в пуле ожидания, пропуская эти ресурсы.

Из http.Transport документов

По умолчанию Transport кэширует соединения для последующего повторного использования. Это может оставить много открытых соединений при доступе ко многим хостам. Это поведение можно управлять с помощью метода CloseIdleConnections для транспорта и полей MaxIdleConnsPerHost и DisableKeepAlives.

Транспорты должны использоваться повторно, а не создаваться по мере необходимости. Транспорты безопасны для одновременного использования несколькими программами.

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

0 голосов
/ 29 апреля 2018

Ваша проблема заключается в том, чтобы не закрывать тело ответа в этой строке:

_, err := httpClient.Get("https://api.ipify.org?format=json")

получите переменную ответа и закройте тело в отложенном состоянии, например:

r, err := httpClient.Get("https://api.ipify.org?format=json")
if err != nil {
    c <- QR{Addr: prox, Res: false}
    return
}
defer r.Body.Close()

c <- QR{Addr: prox, Res: true}

в документах The client must close the response body when finished with it: здесь

...