Go에서는 리소스 관리를 위한 실용적인 접근 방식을 채택합니다. 다른 언어의 try-finally와는 달리, 여기에서는 defer라는 내장 메커니즘이 있습니다. 이 메커니즘은 "지연"된 함수를 기록하고 범위를 벗어날 때 이를 실행합니다. 이 도구는 리소스(파일, 네트워크 연결)를 자동으로 해제하는 데 자주 사용됩니다.
파일이나 연결을 Close 호출하는 것을 잊으면 리소스 누수나 차단이 발생할 수 있습니다. 이는 서버 및 파일 애플리케이션에서 매우 중요합니다. defer를 사용한 지연 호출은 오류나 panic이 발생하더라도 종료 함수가 호출된다는 것을 보장합니다. 그러나 defer를 잘못 사용하면 오류를 초래할 수 있는 특별한 경우도 있습니다: 반복문 내에서 defer를 호출하거나 잘못된 객체를 전달하거나 많은 수의 defer를 사용하면 오버헤드가 발생할 수 있습니다.
항상 리소스를 성공적으로 연 후 즉시 **defer f.Close()**를 호출하여 잊은 채로 닫는 것을 피하세요. 매우 많은 파일을 여는 경우 성능 향상 및 메모리 절약을 위해 조밀한 반복문 내에서 defer를 사용하지 마세요. 파일/리소스 열기를 함수로 감싸서 범위를 최소화하는 것을 권장합니다.
코드 예시:
file, err := os.Open("data.txt") if err != nil { log.Fatal(err) } defer file.Close() // 보장된 닫기 // ... 파일 작업
주요 특징:
defer가 언제 실행되고 그 매개변수는 언제 계산되나요?
defer에서 함수의 매개변수는 defer를 선언하는 순간 즉시 계산되며, defer 실행 시 계산되지 않습니다.
코드 예시:
func main() { a := 1 defer fmt.Println(a) // 1을 기억합니다. a = 42 } // 1을 출력합니다.
defer가 메모리 누수나 지연을 초래할 수 있나요?
네, 많은 파일이나 객체를 여는 반복문에서 defer를 사용하면 각 defer가 지연 호출 스택에 기록되며, 이는 함수에서 나올 때만 정리되므로 불필요한 메모리 증가를 초래할 수 있습니다.
코드 예시:
for i := 0; i < 10000; i++ { f, _ := os.Open("file.txt") defer f.Close() // main 종료 시까지 모든 10000 파일을 열어둡니다. }
f.Close() 호출이 오류를 반환하고 이 오류가 "소멸"되면 어떻게 되나요?
리소스를 닫는 오류는 표준 관행으로 로깅해야 합니다. 이 부분을 무시하면 일시적인 파일이 삭제되지 않거나 네트워크 오류 등으로 인해 파일의 손실이나 부분 저장 현상을 감지하지 못할 수 있습니다.
파일을 처리하는 반복문에서 개발자는 각 파일에 대해 defer f.Close()를 설정합니다. 이로 인해 수만 개의 파일이 동시에 열리게 되어 프로그램 실행이 지연되고, 시스템에서 파일 디스크립터가 고갈됩니다.
장점:
단점:
반복문에서 각 파일을 별도의 함수에서 처리하고, 그 함수에서 defer f.Close()를 단 한 번만 사용하여 즉시 리소스를 해제합니다.
장점:
단점: