Эта статья переведена с (Memory Leaking) Авторские права @ принадлежат оригинальному тексту.
При программировании на языке со сборщиком мусора (GC), как правило, нам не нужно заботиться об утечках памяти, поскольку среда выполнения языка периодически собирает неиспользуемую память. Или частный случай реальной утечки памяти.В оставшейся части этой статьи будет перечислено несколько таких случаев.
Незначительная утечка памяти из-за подстрок
Спецификация Go не указывает, должны ли результирующая строка и базовая строка, участвующие в выражении подстроки, совместно использовать один и тот же базовый блок памяти, в котором размещается базовая последовательность байтов для обеих строк.Стандартный компилятор/среда выполнения Go заставляет их совместно использовать один и тот же базовый блок памяти , Это хороший дизайн, и это мудрый шаг для потребления памяти и процессора, но это может привести к утечкам памяти.
Например, вызов следующей функцииf
, произойдет утечка памяти объемом 1 Мбайт (незначительная), пока переменные уровня пакета не будут изменены в другом месте.s0
.
var s0 string // package level variable |
Чтобы избежать этой небольшой утечки памяти, мы можем преобразовать подстроку в[]byte
значение, то[]byte
значение преобразовано обратноstring
.
func f(s1 string) { |
Недостатком описанного выше метода предотвращения этой небольшой утечки памяти является то, что при преобразовании происходит копирование 50 байтов, один из которых не нужен.
Что мы можем сделать со стандартным компилятором Goоптимизациячтобы избежать единственной копии с небольшими дополнительными затратами на трату байта.
func f(s1 string) { |
Недостатком описанного выше подхода является то, что оптимизации компилятора могут впоследствии дать сбой, а оптимизации могут не работать с другими компиляторами.
Третий способ избежать утечек памяти типов — использовать то, что не поддерживалось до версии Go 1.10.strings.Builder
.
import "strings" |
Недостаток третьего способа в том, что он немного многословен (по сравнению с первыми двумя).
Незначительная утечка памяти, вызванная субсрезами
Подобно нахождению подстроки, нахождение подводных классов также может вызвать легкую утечку памяти. В следующем ниже, вызываяg
После функции, несяs1
Большая часть памяти, занимаемой блоком памяти элемента, будет потеряна (если больше нет значений, ссылающихся на блок памяти).
var s0 []int |
Если мы хотим избежать этой небольшой утечки памяти, мы должны скопироватьs0
30 элементов , так чтоs0
выживание не мешаетs1
Блок памяти элемента освобождается.
func g(s1 []int) { |
Незначительная утечка памяти, вызванная сбросом указателей на уцелевшие элементы среза.
В приведенном ниже коде вызовитеg
После функции присвойте срезуs
Блок памяти для первого элемента теряется.Если последний элемент никогда не используется в качестве элемента какого-либо среза после этого, блок памяти, выделенный для последнего элемента, также теряется.
func g() []*int { |
Если возвращенный фрагмент все еще жив, это предотвратит сборs
основной блок памяти элемента, тем самым предотвращаяs
Два блока памяти, выделенные от первого до последнего элемента, собираются, даже если эти два элемента больше не активны.
Если мы хотим избежать этой небольшой утечки памяти, мы должны сбросить указатели в неживых элементах (здесь, в функцииh
После вызова первый и последний элементы считаются мертвыми).
func h() []*int { |
Нам часто приходится сбрасыватьОперация удаления элемента срезаУказатель на невыживаемый элемент в .
Утечки памяти, вызванные потерянными горутинами
Иногда из-за какой-то логической ошибки в дизайне кода одна или несколько горутин блокируются навсегда, что приводит к тому, что многие блоки кода, используемые в этих горутинах, никогда не удаляются сборщиком мусора Это настоящая утечка памяти.
Например, если следующие функции используются в качестве функции запуска GOROUTINE и передают параметр канала Nil для него, Goroutine всегда будет блокировать. Go Runtime думает, что Goroutine все еще живет, такs
Выделенный блок памяти никогда не будет собран.
func k(c <-chan bool) { |
Мы должны избегать этой логической ошибки.
Финализаторы
Установите финализаторы для участников в циклической справочной группеможет препятствовать сбору всех блоков памяти, выделенных для этой циклической группы ссылок., Это не мелкая, а настоящая утечка памяти.
После того, как следующие функции будут вызваны и завершены,x
а такжеy
Не гарантируется, что выделенный блок памяти будет собран сборщиком мусора в будущем.
func memoryLeaking() { |
Поэтому избегайте установки финализаторов для значений в круговых ссылочных группах.