Thanks Michael. My opinion is 1. It should be mentioned explicitly in the doc that a blocking finalizer will cause future objects with finalizers to leak. Probably next to the "A single goroutine runs all finalizers for a program..." section. 2. Go should provide a way to know about it when it happens. For example, we could have runtime.LastFinalizer() which returns {StartTime, Trace}. Users may choose to monitor it to detect the issue and its source. 3. I am not sure if it is intentional, but the goroutine dump indicates finq only if debug=1 is used. 4. Maybe we can add pprof/sys to indicate such metrics/potential issues? 5. Regarding the single routine vs multi-routine. Yes, this is clear. Did you consider having a finalizer routine per package? I think this is a significant deficit since it break isolation. Either way, I find providing 1 and 2 sufficient.
Do you want me to start a formal discussion in golang/go or will you take it from here? Thanks again. On Wednesday, 19 March 2025 at 15:24:46 UTC+2 Michael Knyszek wrote: > > Unfortunately, this is pretty much how such features tend to be designed > to keep overheads low. > > Er, sorry, this is actually a little more nuanced. Creating a new > goroutine for each finalizer/cleanup could cause a different problem of > generating too many goroutines (so, too much memory being used) in addition > to the cost of creating and scheduling new goroutines, and once that > behavior is relied on it's very difficult to change. For example, > context.AfterFunc has this behavior, and that's an example where the new > goroutine overhead has been reported to us as causing performance issues as > well. I suspect there just isn't going to be one right answer for all > cases. Cleanups and finalizers are relatively low level, so the scales > tilted more toward having users do their own scheduling, at the risk of the > blocking issues you ran into. (As well as the fact that cleanups and > finalizers have more loose guarantees in general.) > > On Wednesday, March 19, 2025 at 9:05:30 AM UTC-4 Michael Knyszek wrote: > >> Sorry you ran into this issue. >> >> Unfortunately, this is pretty much how such features tend to be designed >> to keep overheads low. You make a good point that we should have more >> diagnostics to detect when this happens. We can add a `runtime/metrics` >> metric, or perhaps add extend the capabilities of an experimental debug >> mode I'm working on for cleanups and finalizers (https://go.dev/cl/634599). >> At the very least, I'll make note of this in https://go.dev/doc/gc-guide. >> >> Note also that even though `runtime.AddCleanup` is documented as running >> cleanups concurrently, >> 1. In Go 1.24 we don't actually do that, so it won't help you to switch >> in the short term. I have a patch for Go 1.25 to do that properly. ( >> https://go.dev/cl/650697) >> 2. Even once we can run cleanups concurrently, it's still hazardous to >> spend a long time in a cleanup. The Go 1.25 implementation will not run >> each cleanup in its own goroutine, as that is just too expensive and very >> hard to change. You can still exhaust the finite number of goroutines used >> to run cleanups. >> >> Java Cleaners have a similar limitation in that each Cleaner runs all its >> actions on a single thread. ("The execution of the cleaning action is >> performed by a thread associated with the cleaner. [...] The thread runs >> until all registered cleaning actions have completed and the cleaner itself >> is reclaimed by the garbage collector.", from >> https://docs.oracle.com/javase/9/docs/api/java/lang/ref/Cleaner.html) >> There is a difference here in that you can create as many cleaners as you >> want, AFAICT. >> >> I'll note that we might be able to do something more complicated in the >> future in which we "detach" a cleanup goroutine if we detect that it blocks >> or runs too long at runtime. But just to set expectations, I don't think >> there's a high likelihood that we'll do something like this any time soon. >> On Wednesday, March 19, 2025 at 8:49:59 AM UTC-4 Gavra wrote: >> >>> Yes, even if it was only a few ms, they should have run it in a >>> goroutine. >>> >>> On Wednesday, 19 March 2025 at 14:17:56 UTC+2 Robert Engels wrote: >>> >>>> The docs: >>>> >>>> “ A single goroutine runs all finalizers for a program, sequentially. >>>> If a finalizer must run for a long time, it should do so by starting a new >>>> goroutine.” >>>> >>>> So the code did not follow the api docs - as apparently the close() is >>>> indefinite. >>>> >>>> On Mar 19, 2025, at 6:46 AM, Gavra <gav...@gmail.com> wrote: >>>> >>>> Yes, I intend to open a bug for them. >>>> >>>> I agree that one should not relay on the execution of finalizers. But, >>>> the fact that the runtime just piles them up because one package did wrong >>>> is outrageous. >>>> >>>> By the way, I am not sure why but I can see the mfinal routine only >>>> when running my program from Goland; When I build it manually the routine >>>> is invisible using pprof. >>>> >>>> On Wednesday, 19 March 2025 at 13:38:04 UTC+2 Robert Engels wrote: >>>> >>>>> In fact the code you reference - the close() - does things the Go docs >>>>> warn specifically not to do. >>>>> >>>>> You may be better off using runtime.AddCleanup() >>>>> >>>>> >>>>> >>>>> On Mar 19, 2025, at 6:32 AM, Robert Engels <ren...@ix.netcom.com> >>>>> wrote: >>>>> >>>>> >>>>> >>>>> In principle, I would argue that there is a correctness problem. You >>>>> should not rely on finalizers ever - they are catches and often optional >>>>> - >>>>> so the design relying on finalizers to run is what is broken. >>>>> >>>>> In the real world they can make solving certain problems much easier - >>>>> especially with shared resources. I know Java has deprecated them in lieu >>>>> of other technologies like Cleaners. >>>>> >>>>> >>>>> On Mar 19, 2025, at 6:19 AM, Gavra <gav...@gmail.com> wrote: >>>>> >>>>> >>>>> https://github.com/hirochachacha/go-smb2/blob/c8e61c7a5fa7bcd1143359f071f9425a9f4dda3f/client.go#L1063 >>>>> We are looking for why exactly it blocked (probably incorrect ctx) but >>>>> I think this close should run in a goroutine. >>>>> >>>>> On Wednesday, 19 March 2025 at 12:29:34 UTC+2 Brian Candler wrote: >>>>> >>>>>> On Wednesday, 19 March 2025 at 09:55:58 UTC Gavra wrote: >>>>>> >>>>>> This finalizer blocks the runtime's finalizer goroutine >>>>>> >>>>>> >>>>>> Out of interest, what made it block? Was the finalizer doing some >>>>>> channel communication, for example? >>>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "golang-nuts" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to golang-nuts...@googlegroups.com. >>>>> To view this discussion visit >>>>> https://groups.google.com/d/msgid/golang-nuts/5c7c034d-3bc6-4fe5-82bb-a318310bd82fn%40googlegroups.com >>>>> >>>>> <https://groups.google.com/d/msgid/golang-nuts/5c7c034d-3bc6-4fe5-82bb-a318310bd82fn%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>> . >>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "golang-nuts" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to golang-nuts...@googlegroups.com. >>>>> >>>>> To view this discussion visit >>>>> https://groups.google.com/d/msgid/golang-nuts/6AABBB52-5BC6-4874-900B-C423E37952C4%40ix.netcom.com >>>>> >>>>> <https://groups.google.com/d/msgid/golang-nuts/6AABBB52-5BC6-4874-900B-C423E37952C4%40ix.netcom.com?utm_medium=email&utm_source=footer> >>>>> . >>>>> >>>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "golang-nuts" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to golang-nuts...@googlegroups.com. >>>> >>>> To view this discussion visit >>>> https://groups.google.com/d/msgid/golang-nuts/75da8ea2-c099-483c-969a-ab99a91da2a4n%40googlegroups.com >>>> >>>> <https://groups.google.com/d/msgid/golang-nuts/75da8ea2-c099-483c-969a-ab99a91da2a4n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>>> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/e0e8f836-d614-46df-877a-2bca3d540c0en%40googlegroups.com.