News for hackers. Stuff that matters.
Re:Rust: Dropping heavy things in another thread can make yo... by papaf on Saturday May 30, 2020 @02:20PM (#23363331)
This deallocation trick is neat but in C and C++ you could use a memory pool to do this.

In theory, you could also use a memory pool in Rust but I think the standard library uses malloc without some way of overriding this behaviour.

Re:Rust: Dropping heavy things in another thread can make yo... by vvanders on Saturday May 30, 2020 @02:50PM (#23363582)
You can also use the typed-arena crate[0] or roll your own if you're feeling like cracking open unsafe.

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

Re:Rust: Dropping heavy things in another thread can make yo... by all-fakes on Saturday May 30, 2020 @07:51PM (#23365916)
Typed-arena is a bit limited, because all the allocated values must be of the same type. bumpalo[0] removes that restriction, but it also doesn't run destructors, which can lead to memory and other resource leaks. Another worry I have with bumpalo is that I don't think it's been reviewed thoroughly for unsoundness.

Still, bumpalo has been used to great effect in dodrio[1], a React-like library for Rust with really good performance.

[0]: https://crates.io/crates/bumpalo

[1]: https://github.com/fitzgen/dodrio

Re:Rust: Dropping heavy things in another thread can make yo... by orf on Saturday May 30, 2020 @02:32PM (#23363437)
You can change the global allocator in any rust project. You can write your own easy enough, or use one like jemalloc
Re:Rust: Dropping heavy things in another thread can make yo... by josephg on Saturday May 30, 2020 @07:28PM (#23365772)
Sure; but when you’re using arenas and things like that you usually you will want different objects allocated into different pools (or with different lifetime properties). Rust only lets you pick one allocator for the entire process, so you can’t specify “all the children of this data structure go in arena A, and this other allocation goes into a traditional heap”.

It’s more awkward, but I much prefer Zig’s approach here where everything that allocates takes an allocator as a parameter. Usually the allocator is specified at compile time - in which case zig can generate identical code to the rust compiler. But when you want the flexibility, it’s there.

Aside from compilers, this is heavily used in video games where there’s often a lot of objects that get allocated per frame, and can be discarded all together. And in that case rust’s lifetime tracking would be a huge asset. The dovecot email server (C) also makes superb use of a mix of memory containers for different tasks. Given how messy email parsing is, dovecot is an absolute pleasure to read.

Re:Rust: Dropping heavy things in another thread can make yo... by steveklabnik on Saturday May 30, 2020 @07:40PM (#23365843)
Not in an abstract way, but you can do this. The compiler has (had? It’s been a while) two different major arenas, in my understanding. There’s just no non-global allocator trait yet, so it’s not easy to abstract over.
Re:Rust: Dropping heavy things in another thread can make yo... by andrepd on Saturday May 30, 2020 @08:05PM (#23365993)
>everything that allocates takes the allocator as a parameter

This is also the C++ approach

Re:Rust: Dropping heavy things in another thread can make yo... by afiori on Sunday May 31, 2020 @07:04AM (#23368718)
As someone that is interested in the topic and in Zig's "provide your own allocator" approach I have a question: would it be possible to make an allocator wrapper that moves values to be deallocated to a different thread?

As far as I know it would require both Rust's borrowing semantics and Zig's architectural choice.

From purely my own fan-boy perspective Zig approach is something that I would have really liked for Rust to adopt (I have no idea of which one came first chronologically).

Re:Rust: Dropping heavy things in another thread can make yo... by steveklabnik on Sunday May 31, 2020 @09:08AM (#23369337)
It is not an allocator wrapper, but https://docs.rs/defer-drop/1.0.1/defer_drop/index.html
Re:Rust: Dropping heavy things in another thread can make yo... by francasso on Saturday May 30, 2020 @07:26PM (#23365759)
I don't get this. Usually I either don't care about how stuff is allocated, or when I care I want to be specific about what allocator should be used where. In the second situation just setting a global allocator wouldn't cut it most of the time, I would want support for customization when I instantiate a data structure.
Re:Rust: Dropping heavy things in another thread can make yo... by bauerd on Saturday May 30, 2020 @02:53PM (#23363605)
Think with LD_PRELOAD it is always possible to override the allocator?
Re:Rust: Dropping heavy things in another thread can make yo... by jfkebwjsbx on Sunday May 31, 2020 @12:57AM (#23367307)
That wouldn’t help. The point is to use local allocators which have extra information about the data structures and usage of the memory.

This is routinely done in medium to large C++ programs for different reasons (performance, debuggability...).

Re:Rust: Dropping heavy things in another thread can make yo... by dan-robertson on Saturday May 30, 2020 @06:52PM (#23365551)
Only if it is dynamically linked
Re:Rust: Dropping heavy things in another thread can make yo... by wongarsu on Saturday May 30, 2020 @05:28PM (#23364909)
In a toy raytracer I once wrote in C++, switching from malloc to custom memory pools for small fixed-size objects was a big performance boost. Making free() a noop was another big performance boost, both for deallocation and allocation. Turns out sequentially handing out memory from a big chunk of memory is much easier than keeping track of and reusing empty slots, and it keeps sequentially allocated objects in sequential memory locations.
Re:Rust: Dropping heavy things in another thread can make yo... by folmar on Saturday May 30, 2020 @06:28PM (#23365374)
jemalloc is the answer to the question you did not ask
Re:Rust: Dropping heavy things in another thread can make yo... by estebank on Saturday May 30, 2020 @02:57PM (#23363647)
In Rust you could just call `mem::forget` on whatever heavy thing that you're no longer using is before it would get dropped, but then the programmer is effectively responsible for that memory leak not becoming a problematic leak during refactors.

Edit: this will also break any code that relies on Drop being called for clean up, but that is already a "suspect"/incorrect pattern because there are no assurances that it will ever run.

Re:Rust: Dropping heavy things in another thread can make yo... by kd5bjo on Saturday May 30, 2020 @04:45PM (#23364545)
> There are no assurances that it will ever run.

Yes and no. Whenever control leaves a code block, Rust automatically calls the drop() method of all values still owned by that block. There is no guarantee that control will exit every block (cf. Turing), but a moderately exceptional circumstance needs to occur for this not to happen, like an infinite loop.

Re:Rust: Dropping heavy things in another thread can make yo... by rcxdude on Saturday May 30, 2020 @05:35PM (#23364974)
There's also no guarantee the object won't be moved elsewhere, including into a context which never gets freed (for example, you can construct mem::forget using entirely safe code by forming a cycle of reference-counted boxes). That said, Rust has support for such a concept through the Pin trait (which essentially guarantees an object will not get moved until it is 'Unpinned').
Re:Rust: Dropping heavy things in another thread can make yo... by mcguire on Saturday May 30, 2020 @03:34PM (#23363917)
Isn't that a problem for the RAII approach?
Re:Rust: Dropping heavy things in another thread can make yo... by projektfu on Saturday May 30, 2020 @03:15PM (#23363802)
Yeah, I like Apple’s (Next’s) approach of pool allocation for each run through the event loop. Defer dealloc, drop pool at the end.
Re:Rust: Dropping heavy things in another thread can make yo... by saurik on Saturday May 30, 2020 @03:29PM (#23363887)
Apple's pools are for helping manage reference counts of returned objects (via autorelease) but aren't doing pool allocation (as any of those objects could escape, so you can't do the fast thing of just deallocating the pool). The normal memory allocator is used while in the scope of an autorelease pool.
Re:Rust: Dropping heavy things in another thread can make yo... by projektfu on Saturday May 30, 2020 @06:21PM (#23365309)
True, I was thinking the same after I posted. Maybe I’m thinking more of Apache’s approach and how it gets some of the benefits of a fork-per-request server without the overhead.
Re:Rust: Dropping heavy things in another thread can make yo... by andrekandre on Saturday May 30, 2020 @09:27PM (#23366420)
right, so if you do

@autoreleasePool { [[[SomeObject alloc] init] autorelease]; }//someobject is release after exiting this scope

//inside main runloop, not inside @autorelease{} [[[AnotherObject alloc] init] autorelease];

//AnotherObject will be release at end of main runloop

[[NotAutoreleased alloc] init]; //will leak past runloop iteration

is that understanding correct?

Re:Rust: Dropping heavy things in another thread can make yo... by mcguire on Saturday May 30, 2020 @03:33PM (#23363912)
Unless your destructors do more than deallocation, in which case you will leak whatever other resource you're managing.
Re:Rust: Dropping heavy things in another thread can make yo... by MaxBarraclough on Saturday May 30, 2020 @04:19PM (#23364302)
A pool can invoke destructors when it is cleared. Might take a bit of overhead (if the pool is to support arbitrary classes), but you could retain the fast pointer-bump allocation.
Re:Rust: Dropping heavy things in another thread can make yo... by ShroudedNight on Saturday May 30, 2020 @07:59PM (#23365959)
Not Rust, C++, but in case anybody wants an example: https://github.com/eclipse/omr/commit/fd99ca42fdbed76cc00e68...

TR::Region is the slab allocator used by the JIT in OpenJ9/OMR. The linked commit adds functionality for calling destructors of arbitrary types allocated in the Region.

Re:Rust: Dropping heavy things in another thread can make yo... by MaxBarraclough on Sunday May 31, 2020 @02:18PM (#23371420)
Interesting, thanks. Seems to require use of a common base class though, i.e. to use a class with this pool, you have to inherit from Destructable, or else create a subclass that does. Seems ugly. Perhaps that's the only way it can be done in C++ though.
Re:Rust: Dropping heavy things in another thread can make yo... by projektfu on Monday June 01, 2020 @03:45PM (#23382873)
It does create an object with that base class for the allocator but returns an object of the type you want from the allocator, using a template (Region::Instance<T>). So the API user only sees the types it's interested in.
Re:Rust: Dropping heavy things in another thread can make yo... by CoolGuySteve on Saturday May 30, 2020 @02:53PM (#23363608)
Even just keeping a free list and deallocating it’s elements at an idle time is probably cheaper and faster than spawning a thread.
Re:Rust: Dropping heavy things in another thread can make yo... by jomohke on Saturday May 30, 2020 @06:10PM (#23365223)
You can easily use a custom global allocator in Rust:

    #[global_allocator]
    static GLOBAL: MyAllocator = MyAllocator;
Re:Rust: Dropping heavy things in another thread can make yo... by pjmlp on Saturday May 30, 2020 @02:35PM (#23363457)
In C++/WinRT the same approach is taken, because you cannot just use a memory pool for COM.