-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed memory leak caused by SetFinalizer
- Loading branch information
Showing
4 changed files
with
121 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package ex | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
type deferred struct { | ||
callback func() error | ||
fromFile string | ||
fromLine int | ||
gcUnclosedDetector *gcUnclosedDetector | ||
} | ||
|
||
func newDeferred( | ||
callback func() error, | ||
fromFile string, | ||
fromLine int, | ||
) *deferred { | ||
deferred := &deferred{ | ||
callback: callback, | ||
fromFile: fromFile, | ||
fromLine: fromLine, | ||
} | ||
deferred.gcUnclosedDetector = newGCUnclosedDetector(deferred.String()) | ||
|
||
return deferred | ||
} | ||
|
||
func (deferred *deferred) String() string { | ||
if deferred.fromFile == "" { | ||
return "deferred close" | ||
} | ||
|
||
return fmt.Sprintf( | ||
"deferred close initiated by %s:%d", | ||
deferred.fromFile, | ||
deferred.fromLine, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package ex | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"runtime" | ||
) | ||
|
||
var onGarbageCollectUnclosed = func(err error) { | ||
fmt.Fprintln(os.Stderr, err) | ||
} | ||
|
||
// OnGarbageCollectUnclosed changes what happens when a Terminator | ||
// gets garbage collected without the Close method having been called. | ||
// | ||
// The default behaviour is to write an error message to stderr. | ||
// Use this for example if you prefer to panic or pass it to your log | ||
// system instead of stderr. | ||
func OnGarbageCollectUnclosed(handler func(error)) { | ||
if handler == nil { | ||
panic("Cannot set a nil garbage collect unclosed handler") | ||
} | ||
|
||
onGarbageCollectUnclosed = handler | ||
} | ||
|
||
type gcUnclosedDetector struct{ | ||
description string | ||
isClosed bool | ||
} | ||
|
||
func newGCUnclosedDetector(description string) *gcUnclosedDetector { | ||
detector := &gcUnclosedDetector{ | ||
description: description, | ||
isClosed: false, | ||
} | ||
|
||
runtime.SetFinalizer(detector, (*gcUnclosedDetector).finalizer) | ||
|
||
return detector | ||
} | ||
|
||
func (detector *gcUnclosedDetector) finalizer() { | ||
if detector.isClosed { | ||
return | ||
} | ||
|
||
onGarbageCollectUnclosed(fmt.Errorf( | ||
"The Close method of the terminator containing a %s was never called before being garbage collected.", | ||
detector.description, | ||
)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters