News for hackers. Stuff that matters.
Re:Rust: Dropping heavy things in another thread can make yo... by chowells on Saturday May 30, 2020 @01:33PM (#23362925)
This is the standard problem with tracing data structures to free them. You frequently run into it with systems based on malloc/free or reference counting. The underlying problem is that freeing the structure takes time proportional to the number of pointers in the structure it has to chase.

Generational/compacting GC has the opposite problem. Garbage collection takes time proportional to the live set, and the amount of memory collected is unimportant.

It's actually a lot to be said for rust that the ownership system lets you transfer freeing responsibility off-thread safely and cheaply in order to not have it block the critical path.

But overall, there's nothing really unexpected here, if you're familiar with memory management.

Re:Rust: Dropping heavy things in another thread can make yo... by Jasper_ on Saturday May 30, 2020 @01:43PM (#23363017)
One of my favorite papers by Bacon et al expands on this intuition that garbage collection and reference counting are opposite tradeoffs in many respects, and gives a formal theory for it. My views on gc/rc haven't been the same since.

http://researcher.watson.ibm.com/researcher/files/us-bacon/B...

Re:Rust: Dropping heavy things in another thread can make yo... by pron on Saturday May 30, 2020 @03:13PM (#23363780)
That's a great paper, but one important thing to point out is that some production-grade tracing GCs are on the sophisticated end of that paper, while almost all reference counting GCs are on the rather primitive end. Given the same amount of effort, it's easier to get a reasonable result with reference-counting, but there are industrial-strength tracing GCs out there that have had a lot of effort put into them.
Re:Rust: Dropping heavy things in another thread can make yo... by jeffdavis on Saturday May 30, 2020 @05:23PM (#23364860)
"Generational/compacting GC has the opposite problem. Garbage collection takes time proportional to the live set, and the amount of memory collected is unimportant."

Takes time proportional the live set times the number of GC runs that happen while the objects are alive. In other words, the longer the objects live, the more GC runs have to scan that object (assuming there is enough activity to trigger the GC), and the worse GC looks.

Re:Rust: Dropping heavy things in another thread can make yo... by titzer on Sunday May 31, 2020 @06:30AM (#23368571)
This is most decidedly not true for generational GCs, and for concurrent GCs, the tracing work happens asynchronously and in parallel, on other cores, not taking time on the main thread.
Re:Rust: Dropping heavy things in another thread can make yo... by jeffdavis on Sunday May 31, 2020 @11:00AM (#23369968)
You still have to scan the oldest generation at some point; otherwise (assuming some activity) you'll be leaking memory there over time.

Moving the work to another core doesn't really change my statement.

Aside: I wonder if it's feasible to switch to reference counting for the oldest generation? That would move the problem back to deallocation. I'm not sure if that's a good trade-off, but it would be interesting.

Re:Rust: Dropping heavy things in another thread can make yo... by tsimionescu on Sunday May 31, 2020 @06:51AM (#23368654)
It's still true for generational GC, but the costs are more complicated. Even objects in the oldest generation are periodically scanned in most implementations (though there are some, like Clozure CL's GC, that never scan the old generation automatically).

But generational GCs do improve massively on this problem.

Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @01:42PM (#23363000)
> the ownership system lets you transfer freeing responsibility off-thread safely and cheaply in order to not have it block the critical path

This can also trivially be done in other languages. Atomically append your pointer to a queue of "large things that need to be freed" and move on as though you had actually called free.

Within a particularly time sensitive loop you can even opt to place pointers into a preallocated array locally. Then once per loop iteration swap that array with the thread handling the deallocations for you. It eats up a bit of CPU time but can significantly reduce latency.

Re:Rust: Dropping heavy things in another thread can make yo... by jacobparker on Saturday May 30, 2020 @02:49PM (#23363571)
OP said safely; what you're describing isn't safe in, say, C++ in the same sense that it is in Rust.
Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @04:16PM (#23364283)
Isn't that essentially a tautology? Manual memory management and threading in such languages lacks safety guarantees to begin with.
Re:Rust: Dropping heavy things in another thread can make yo... by im3w1l on Saturday May 30, 2020 @04:49PM (#23364586)
A lot of C++ code depends on deallocation order for correctness. Like a destructor may want to say bye-bye to a pointed-to-object, and if you reverse order of deallocation, that pointer may be dangling.

Consider this code

    {
        Window a;
        ClickHandler* b = new ClickHandler(&a);
        delete b;
    }
Let's say b tries to deregister itself when it's deleted. This code will work as written. But if you defer the deletion of b, then stack allocated Window a may already be gone.
Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @08:18PM (#23366052)
I never meant to imply that you could use such tricks without considering the lifetimes of references. Manual memory management already requires being mindful of those though so it's nothing unique to the described situation. Yes Rust offers an advantage here, but it's the same one it offers everywhere else so it doesn't seem relevant to me.

That being said, it seems like most cases where such an approach is worthwhile involve large nested data structures that involve lots of pointer chasing to traverse. All cases I've encountered so far were bulk stores that didn't involve actively interacting with external objects.

Re:Rust: Dropping heavy things in another thread can make yo... by im3w1l on Sunday May 31, 2020 @05:46AM (#23368393)
Replying to myself: I guess you could run the destructors in order, but keep the memory around a bit longer.
Re:Rust: Dropping heavy things in another thread can make yo... by loufe on Saturday May 30, 2020 @01:37PM (#23362964)
I've not worked with any language thus far without automatic garbage collecting, so this was definitely a neat read for me. It sounds rather elegant.
Re:Rust: Dropping heavy things in another thread can make yo... by burpsnard on Saturday May 30, 2020 @07:37PM (#23365822)
It's worth popping the hood and getting your fingers dirty. C was written in an era where memory was a scarce and precious resource to be grudgingly used if absolutely necessary
Re:Rust: Dropping heavy things in another thread can make yo... by tsimionescu on Sunday May 31, 2020 @07:33AM (#23368869)
Please note that C is quite a few years older than the first GC languages. LISP1.5, ALGOL-68 and APL all had garbage collectors before C even existed.

Not to say that it's not worth it to learn manual memory management as well, but it is important not to think that GCs are a fancy modern tool, and that greybeards would never touch one. There were greybeards using punch cards and programming in a GC language, with output printed out on paper.

Re:Rust: Dropping heavy things in another thread can make yo... by arcticbull on Saturday May 30, 2020 @01:43PM (#23363010)
> This is the standard problem with tracing data structures to free them. You frequently run into it with systems based on malloc/free or reference counting. The underlying problem is that freeing the structure takes time proportional to the number of pointers in the structure it has to chase.

That doesn't seem to make intuitive sense. A GC has the same problem.

A garbage collector has to traverse the data structure in a similar way to determine whether it (and it's embedded keys and values) are part of the live set or not, and to invoke finalizers. You're beginning your comparison after the mark step, which isn't a fair assessment since what Rust is doing is akin both both the mark and sweep phases.

The only way to drop an extensively nested structure like this any faster than traversing it would be an arena allocator, and forgetting about the entire arena.

The difference between a GC and this kind of memory management is that the GC does the traversal later, at some point, non-deterministically. Rust allows you to decide between deallocating it in place, immediately, or deferring it to a different thread.

Re:Rust: Dropping heavy things in another thread can make yo... by chowells on Saturday May 30, 2020 @01:58PM (#23363154)
I said generational/compacting collector. You're talking about a mark and sweep collector.

A generational/compacting collector traverses pointers from the live roots, and copies everything it finds to the start of its memory space, and then declares the rest unused. If there is 1GB of unused memory, it's irrelevant. Only the things that can be reached are even examined.

As I said, this has the opposite problem. When the live set becomes huge, this can drag performance. When the live set is small, it doesn't matter how much garbage it produces, performance is fast.

Re:Rust: Dropping heavy things in another thread can make yo... by arcticbull on Saturday May 30, 2020 @02:02PM (#23363176)
How are finalizers invoked if the structure isn't traversed? Would it just be optimized away none of the objects have finalizers? Hence my suggestion about the area allocators being a better point of comparison.
Re:Rust: Dropping heavy things in another thread can make yo... by zucker42 on Saturday May 30, 2020 @02:45PM (#23363534)
Java is an example of a language with a generational copy collector by default. Most objects in Java don't have a finalizer, since after all the main point of, for example, destructors in C++ is to make sure you don't leak memory, which the GC solves. But when the `finalize` method is used is causes significant overhead.

> Objects with finalizers (those that have a non-trivial finalize() method) have significant overhead compared to objects without finalizers, and should be used sparingly. Finalizeable objects are both slower to allocate and slower to collect. At allocation time, the JVM must register any finalizeable objects with the garbage collector, and (at least in the HotSpot JVM implementation) finalizeable objects must follow a slower allocation path than most other objects. Similarly, finalizeable objects are slower to collect, too. It takes at least two garbage collection cycles (in the best case) before a finalizeable object can be reclaimed, and the garbage collector has to do extra work to invoke the finalizer. [1]

Sure, you're technically correct that if the objects all had finalizers that did the same thing as C++ destructors, it would be equivalent, but because of the existence of a GC we don't have to do any work for most objects. A GC is equivalent to an arena allocator in this sense.

Another point is the C++/Rust pattern of each object recursively freeing the objects it owns presumably leads to slower deallocation, because in the general case it involves pointer following and non-local access.

[1] https://www.ibm.com/developerworks/java/library/j-jtp01274/i...

Re:Rust: Dropping heavy things in another thread can make yo... by pron on Saturday May 30, 2020 @03:15PM (#23363805)
Which is why finalizers in Java have been officially deprecated [1] and might be removed altogether in a future release.

[1]: https://docs.oracle.com/en/java/javase/14/docs/api/java.base...

Re:Rust: Dropping heavy things in another thread can make yo... by cesarb on Saturday May 30, 2020 @10:14PM (#23366621)
Unfortunately, the alternative they recommend (Cleaner) only exists since Java 9, so it cannot be used by libraries that wish to remain compatible with Java 8 (which, in my experience, is most or all of them; so far, I haven't seen any Java library which has dropped compatibility with Java 8, and many only recently dropped compatibility with Java 6 or 7).
Re:Rust: Dropping heavy things in another thread can make yo... by altfredd on Sunday May 31, 2020 @01:12AM (#23367368)
The actual alternative is PhantomReference, which exists since ancient times. Cleaner simply provides safe way to use PhantomReferences, which are rather tricky to use (by Java standards).
Re:Rust: Dropping heavy things in another thread can make yo... by msclrhd on Saturday May 30, 2020 @03:31PM (#23363905)
Destructors in C++ aren't just for making sure you leak memory. They are used for many lifetime controlled things such as: 1. general resource cleanup (file handle, database connection, etc.) using RAII (Resource Aquisition Is Initialization); 2. tracing function entry/exit.
Re:Rust: Dropping heavy things in another thread can make yo... by mcguire on Saturday May 30, 2020 @03:42PM (#23363962)
Apparently, that doesn't work in Rust: https://news.ycombinator.com/item?id=23363647
Re:Rust: Dropping heavy things in another thread can make yo... by the8472 on Saturday May 30, 2020 @04:11PM (#23364228)
It does work in rust. you just cannot rely on Drop for memory-safety. If you mem::forget a struct that holds onto some other resource then all that means is that you're committing that resource to the lifetime of the process. We usually call that a leak but it can be intentional.
Re:Rust: Dropping heavy things in another thread can make yo... by the_why_of_y on Sunday May 31, 2020 @04:37AM (#23368138)
By that argument, it doesn't work in C++ either because std::unique_ptr::release() exists.
Re:Rust: Dropping heavy things in another thread can make yo... by pdpi on Saturday May 30, 2020 @04:04PM (#23364174)
In the JVM the equivalent to RAII is implemented with try-with-resource/Autocloseable instead.
Re:Rust: Dropping heavy things in another thread can make yo... by cesarb on Saturday May 30, 2020 @10:21PM (#23366642)
In my experience, try-with-resources is inferior to RAII, since it's very easy to forget (that is, it's very easy to do "Foo x = bar();" instead of "try (Foo x = bar()) { ... }"), leading to resource leaks. More than once I have added a finalizer to an AutoCloseable class just to warn loudly if close() hasn't been called; unfortunately, there's no way that I know of to suppress the finalizer once close() is called, so the GC still has to do all the work to call the finalizer even when the class was used correctly.
Re:Rust: Dropping heavy things in another thread can make yo... by jfkebwjsbx on Sunday May 31, 2020 @01:07AM (#23367352)
> after all the main point of, for example, destructors in C++ is to make sure you don't leak memory, which the GC solves

No, C++ destructors are used for finalizers, not memory management.

Memory deallocation is a particular use case for finalizers which is avoided when performance is a concern.

> Another point is the C++/Rust pattern of each object recursively freeing the objects it owns presumably leads to slower deallocation, because in the general case it involves pointer following and non-local access.

No, a program that does pointer chasing and has to deallocate many small allocations is badly designed. If you are going to do that, using a GC language would be much better.

Re:Rust: Dropping heavy things in another thread can make yo... by zucker42 on Sunday May 31, 2020 @12:10PM (#23370458)
> No, C++ destructors are used for finalizers, not memory management.

In the original comment I may have overstated this. I was ignoring the other uses of destructors because the context of the discussion was memory management. But memory management is a huge portion of what destructors do in C++. Consider a vector of strings (`vector<string>`). The destructor deallocates the memory for all the strings, then deallocates the memory for the vector.

> No, a program that does pointer chasing and has to deallocate many small allocations is badly designed. If you are going to do that, using a GC language would be much better.

How do you deallocate all of the nodes in a binary tree? As far as I can tell, you either have to pointer chase or use a custom allocation strategy. At some point with the second option, you're basically creating an ad-hoc garbage collector.

But I think we may be in vigorous agreement here, since my comment was about the general tradeoff between garbage collection and tracing data structures. I was trying to defend the original assertion that with tracing, "freeing the structure takes time proportional to the number of pointers in the structure it has to chase" while "garbage collection [or at least copy collection] takes time proportional to the live set".

Re:Rust: Dropping heavy things in another thread can make yo... by jfkebwjsbx on Monday June 01, 2020 @10:25AM (#23378773)
> Consider a vector of strings (`vector<string>`). The destructor deallocates the memory for all the strings, then deallocates the memory for the vector.

A vector (or binary tree as you mentioned later) of heap allocated elements in a performance critical path is a likely candidate to be redesigned if possible.

> As far as I can tell, you either have to pointer chase or use a custom allocation strategy. At some point with the second option, you're basically creating an ad-hoc garbage collector.

A custom, ad-hoc strategy is the way to go if you need them dynamically allocated and performance at the same time, yeah.

I wouldn't call that a GC, though. A GC usually refers to a global solution.

> But I think we may be in vigorous agreement here

Sounds like it!

Re:Rust: Dropping heavy things in another thread can make yo... by tsimionescu on Sunday May 31, 2020 @08:00AM (#23368976)
> No, a program that does pointer chasing and has to deallocate many small allocations is badly designed. If you are going to do that, using a GC language would be much better.

It is debatable whether using it is good or bad design, but at least the C++ std lib does offer a data structure which requires exactly this kind of deallocation: std::list and std::forward_list. And, given the cache characteristics of array VS linked list implementations, I would guess that most uses of std::list occur for huge lists that get written to often, as that seems to be the only case where the big-O advantage of list inster/delete would actually materialize into any performance benefit over a std::vector.

Re:Rust: Dropping heavy things in another thread can make yo... by mcguire on Saturday May 30, 2020 @03:40PM (#23363949)
Maintain a collection of objects with finalizers associated with the generation; when an object is moved out of the generation, move the finalizer record with it. Then, just before the generation is discarded, run the finalizers.

If the finalizers do something stupid like resurrect the object, have the runtime system notify someone with the authority to go beat the programmer with a stick.

Re:Rust: Dropping heavy things in another thread can make yo... by Avi-D-coder on Saturday May 30, 2020 @08:32PM (#23366128)
Interestingly for the Rust GC I'm working both Drop and finalizers will be supported.

Do you happen to offer beat the programmer with a stick as a service?

Re:Rust: Dropping heavy things in another thread can make yo... by mcguire on Monday June 01, 2020 @02:26PM (#23381913)
Unfortunately, no, but you are going to need it.

I was fooling with a cycle-collected reference counter for Rust for a while, but eventually gave up because of the difficulty in handling finalizers.

Re:Rust: Dropping heavy things in another thread can make yo... by pcl on Saturday May 30, 2020 @02:35PM (#23363461)
Many languages allow a class to avoid declaring a finalized, for just this reason.

The JVM is notable in this regard. And thus, most classes that compile to Java bytecode offer no-finalizer semantics.

Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @02:35PM (#23363460)
My understanding is that finalizers are special cased for a generational GC, have a tendency to introduce significant overhead, and (as with any GC scheme) generally run at unpredictable times. My impression is that RAII idioms are strongly discouraged in conjunction with most GC ecosystems.
Re:Rust: Dropping heavy things in another thread can make yo... by tsimionescu on Sunday May 31, 2020 @08:13AM (#23369039)
Actually, RAII idioms are generally encouraged, but finalizers are not. For the rare few classes that hold resources in GC languages, the Resource is usually Acquired at Initialization as well, and released in a special method (IDisposable.Dispose() in C#, AutoCloseable.Close() in Java). There is also usually some special syntax for automatically calling this syntax when the object exits some scope, though that scope usually has to be declared by the user (using(), try-with-resources, with() in Python etc.).

The biggest difference I know of is that the 'holds-resources' property does not propagate automatically like it does in C++. It's not that hard to always remember to call using(file = new File()) [...]. However, it's much easier to forget that you have a File field in your class which you initialize in the constructor, and so your class must itself be declared IDisposable/AutoCloseable etc.

Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Sunday May 31, 2020 @07:17PM (#23373893)
This is a really good point. I had completely overlooked various deterministic resource cleanup idioms as being equivalent to RAII in all but name.
Re:Rust: Dropping heavy things in another thread can make yo... by tsimionescu on Sunday May 31, 2020 @07:34AM (#23368878)
Even mark-and-sweep collectors only mark starting from GC roots, they don't mark through unreachable objects.
Re:Rust: Dropping heavy things in another thread can make yo... by pron on Saturday May 30, 2020 @03:19PM (#23363835)
> A garbage collector has to traverse the data structure in a similar way to determine whether it (and it's embedded keys and values) are part of the live set or not

Yes, but in practice tracing in a tracing GC is done concurrently and with the help of GC barriers that don't require synchronization and so are generally cheaper than the common mechanisms for reference-counting GC.

> and to invoke finalizers

As others have said, finalizers are very uncommon and, in fact, have been deprecated in Java.

Re:Rust: Dropping heavy things in another thread can make yo... by tsimionescu on Sunday May 31, 2020 @07:37AM (#23368894)
No, they are actually fundamentally wrong. GCs never scan garbage - they only scan objects that are referenced from a GC root.

Note that the problem appears in a different place: if your large structure is actually not garbage, then every GC pass will have to scan it to see what other objects it is keeping alive.

Re:Rust: Dropping heavy things in another thread can make yo... by pron on Sunday May 31, 2020 @08:39AM (#23369182)
Not every GC pass. Some modern GCs (like OpenJDK's default GC, G1) track mutation and maintain "remembered sets." They only need to scan objects that have changed since the last scan (they're actually even more efficient than that, but this is a simplification). In addition, when this scanning is required, it is performed concurrently to the application, so the technique of moving the work to a separate thread is done automatically.
Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @01:54PM (#23363117)
> The only way to drop an extensively nested structure like this any faster than traversing it would be an arena allocator, and forgetting about the entire arena.

Isn't that incompatible with RAII though?

Re:Rust: Dropping heavy things in another thread can make yo... by arcticbull on Saturday May 30, 2020 @01:59PM (#23363162)
You can handle this in Rust pretty neatly with lifetimes. There's a bunch of crates that do this. [1]

[1] https://crates.io/crates/typed-arena

Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @02:22PM (#23363352)
That's a neat library but as far as I can tell it doesn't avoid any traversal or cleanup code. It appears to delay the cleanup so it all happens at once. That's certainly useful, but if you have RAII the traversal still has to happen at some point.
Re:Rust: Dropping heavy things in another thread can make yo... by winstonewert on Saturday May 30, 2020 @03:55PM (#23364089)
It avoids it if your type has no-op drop implementation. So if you use typed-arena for objects which don't own resources, they all get dropped in one massive deallocation and don't have to be traversed.

EDIT: and then I noticed that you mentioned RAII... Right, if the object own some sort of resources that doesn't apply.

Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @04:49PM (#23364576)
No worries. And to clarify, in context the point is that traversal fundamentally can't be avoided in the case of RAII. This defeats (what I see as) the primary use case of an arena allocator - deallocating an arbitrarily large chunk of contiguous memory in O(1) time regardless of object count.

Of course this is all somewhat tangential to the original topic of generational GCs, where the RAII idiom also has significant negative impacts. The performance characteristics would otherwise be O(n) based on the live set and thus similar to an arena allocator in terms of the ability to dispose of an arbitrarily large number of objects efficiently.

Re:Rust: Dropping heavy things in another thread can make yo... by winstonewert on Saturday May 30, 2020 @05:39PM (#23365005)
I'm not sure its fair to say it defeats that use case. It only defeats that use case if you need RAII. Furthermore, in my experience, an arena is most useful when you allocate lots of small objects which is the least likely to case to need RAII.
Re:Rust: Dropping heavy things in another thread can make yo... by Reelin on Saturday May 30, 2020 @08:24PM (#23366078)
I think we're violently agreeing?

RAII is the only use case I was speaking of there. Way back up thread the original post I responded to was talking about arena allocators in comparison to a generational GC and finalizers. The point is that a generational GC doesn't handle finalizers well, but neither does an arena allocator!

Re:Rust: Dropping heavy things in another thread can make yo... by winstonewert on Saturday May 30, 2020 @09:08PM (#23366329)
Yes. We are violently agreeing
Re:Rust: Dropping heavy things in another thread can make yo... by all-fakes on Saturday May 30, 2020 @07:55PM (#23365942)
Yes. Some libraries, like typed-arena (and Rust's built-in Vec), will traverse the structure and call the drop implementations, and others, like bumpalo, will just leak the resources.
Re:Rust: Dropping heavy things in another thread can make yo... by tsimionescu on Sunday May 31, 2020 @07:52AM (#23368947)
> That doesn't seem to make intuitive sense. A GC has the same problem.

> A garbage collector has to traverse the data structure in a similar way to determine whether it (and it's embedded keys and values) are part of the live set or not, and to invoke finalizers.

All garbage collectors start from live objects and only scan those. Then, whatever objects they have not scanned get collected. In copying collectors (like most generational ones), this means that garbage is never touched.

In the mark-and-sweep algorithms, the mark phase still never touches the unreachable objects. However, the sweep phase does need to return those objects to the free list, so it will have to walk them. It will still not do it the same way as malloc/free, as it can walk the heap in order and free unmarked objects as it encounters them, no need to follow pointers, so it may still have better cache performance.

Finalizers introduce extra difficulty, but still the behavior is fundamentally different. What usually happens is that objects which have finalizers are usually remembered in a special list which acts as a GC root itself. When they are only reachable from that list, they get marked so that the finalize will run (usually on a special Finalizer thread). When the Finalizer is finished, and assuming the object was not resurrected, they get removed from the Finalizer list, and now they are not reachable from anywhere at all, so the next GC will finally clean them up. Usually, there is also some API for user code to mark a Finalizable object as 'finalized', which essentially removed it from the Finalizer list early and allows it to be collected as normal, without going through the above process.

And yes, having a large number of finalizable objects in your memory is usually considered a very bad idea. Generally, they are only recommended as a fail-safe measure: you are supposed to do explicit cleaning, but as a fail-safe, to avoid your program crashing in production if a connection or file leak was missed, you also have the Finalizer to throw buckets of water out of your boat (but you should really notice that it is happening and plug that leak, rather then relying on the bucketeer).

Re:Rust: Dropping heavy things in another thread can make yo... by mcguire on Saturday May 30, 2020 @03:37PM (#23363930)
Finalizers/destructors do not work well in garbage collected languages, for that very reason.
Re:Rust: Dropping heavy things in another thread can make yo... by saagarjha on Saturday May 30, 2020 @01:44PM (#23363027)
Usually in a background thread ;)
Re:Rust: Dropping heavy things in another thread can make yo... by arcticbull on Saturday May 30, 2020 @01:49PM (#23363059)
Indeed. The difference is this is happening deterministically, in place (with an optional deferral). A garbage collector has all sorts of different trade-offs.