메모리 누수
비록 고루틴이 다른 쓰레드에 비해 가볍긴 하지만 메모리를 사용하는 것은 당연할 것이다.
그렇기에 사용하진 않지만 살아있는 고루틴은 프로세스의 메모리를 쓸데없이 낭비하게 될 것이다.
이런 현상을 메모리 누수라 한다. 메모리 누수를 관리하는 방법을 살펴보자.
누수 관리
누수가 일어나는 예시
package main
import (
"fmt"
)
func main() {
doWork := func(strings <-chan string) <-chan interface{} {
completed := make(chan interface{})
go func() {
defer fmt.Println("doWork existed")
defer close(complted)
for s := range strings {
fmt.Println(s)
}
}()
return completed
}
doWork(nil)
fmt.Println("Done")
}
예제에서는 doWork에 nil 채널을 전달하는 것을 볼 수 있다. nil 채널을 수신하는 것은 대기를 유발하기 때문이다. 그로인해 doWork는 어떠한 일도 하지 않지만 메인 고루틴이 죽을 때 까지 메모리에 doWork 프로세스는 계속해서 메모리를 차지하고 있을 것이다.
이것을 방지하기 위해 사용할 수 있는 하나의 기법은 for-select 를 사용하는 것이다.
누수를 관리할 수 있는 예시
package main
import (
"fmt"
"time"
)
func main() {
doWork := func(done <-chan interface{}, strings <-chan string) <-chan interface{} {
terminated := make(chan interface{})
go func() {
defer fmt.Println("doWork exited.")
defer close(terminated)
for {
select {
case s := <-strings:
fmt.Println(s)
case <-done:
return
}
}
}()
return terminated
}
done := make(chan interface{})
terminated := doWork(done, nil)
go func() {
time.Sleep(1 * time.Second)
fmt.Println("Canceling doWork goroutine...")
close(done)
}()
<-terminated
fmt.Println("Done")
}
결과
Canceling doWork goroutine...
doWork exited.
Done
done 채널이 일반적으로 첫 번째 매개 변수를 차지한다고 한다. 코드를 살펴보면 strings 채널에 nil을 전달했지만 고루틴은 성공적으로 마무리 되는 것을 볼 수 있다.
'Study > Go' 카테고리의 다른 글
[Go] 고루틴(GoRoutine) 심화(7) - 파이프라인 (0) | 2022.06.24 |
---|---|
[Go] 고루틴(GoRoutine) 심화(6) - 고루틴 에러 처리 (0) | 2022.06.20 |
[Go] 고루틴(GoRoutine) 심화(4) - channel (0) | 2022.05.15 |
[Go] 고루틴(GoRoutine) 심화(3) - sync.Pool (0) | 2022.05.13 |
[Go] 고루틴(GoRoutine) 심화(2) - 클로저 함수, 메모리 (0) | 2022.04.28 |