#garena: a simple (and experimental) arena allocator in Go

43 messages · Page 1 of 1 (latest)

placid solstice
shadow osprey
#

kinda curious how come
ArenaInit doesn’t return an arena? also what happens if you want to drop the arena while the other objects are live

placid solstice
#

I'm using basically the same implementation in C, but there's no GC over there. Arenas are good for doing multiple allocations at once and "freeing" all at once, also, if you're running a hot loop that does a lot of allocations, you can avoid the GC overhead (as you can see in the benchmarks)

#

<3ns/iteration with arena, >120000ns/iteration with the garbage collected allocator. Insane improvement.

#

BUT, I'm not sure about how the runtime will deal with that, again, I'm assuming that the runtime does not know about the existence of the pointers allocated with the arena.

shadow osprey
#

I got that it does init, I am asking why isn’t it « NewArena » instead, what’s the value in forcing the caller to pass a reference

#

there is probably something off with your benchmark, 3ns is probably « optimized away »

#

a bug you have for instance is you don’t zero the memory you return (when reused/past the first time where go does it for you)

placid solstice
#

But whatever, that's just a proof of concept.

#

In production is complicated, because there will be conflicts with the GC. It would work well with the GC disabled.

shadow osprey
#

it is a bug if you want to use the objects or slices returned the same way go without your arena does

placid solstice
shadow osprey
#

go code assumes zero values for everything, it's not exactly optional part of the expectation/language

#

so ther reason for the signature of your constructor is just because you kinda ported it from C ?

placid solstice
shadow osprey
#

it's not "sometimes it's useful", taking a slice for instance

make(T, 0, sz) would be ok-ish to not clear; but make(T, sz, sz) must clear

#

if you don't need it cleared you'd use the first one

placid solstice
#

Now the arena is only 132% faster than the default GC allocator. But I think that the throughput will increase with multiple live pointers, since the GC will have less work to do.

shadow osprey
#

it's more idiomatic but

func ArenaInit(size uintptr) Arena {

should return *Arena (given that's what ArenaAlloc* takes) and probably just be called New() so with your package it becomes

a := garena.New(sz)
#

ditto for dropping the prefix in all the functions, given the stutter with the package name (there are linters btw that will tell you as much)

placid solstice
#

Methods as far as I know can't be generic, right?

shadow osprey
#

yeah but they are still in your package

placid solstice
#

It's right. I forgot I'm not writing C hahaha.

shadow osprey
#

it shows 🙂 go is close but isn't C

for instance

func Foo() *Bar {
  // local var
  x := Bar{...}
  return &x // address of local! oh nooo! (it's fine/idiomatic)
}

is horrible for a C/C++ programmer at first but happens to be idiomatic go

shadow osprey
#

excellent - and good job on postponing cost of zeroing at the end (ie might never be paid if not recycling)

placid solstice
#

Thank you for the tips!

shadow osprey
#

yw!

placid solstice
#

Now I'm allocating directly from the OS via syscall.Mmap, also added new benchmarks.

shadow osprey
#

does it make a difference, assuming there aren't a zillion arenas anyway / they get recycled ?

placid solstice
#

I'm trying to avoid problems with the GC, if it follows the pointers allocated within the arena there will be unnecessary CPU usage/increased latency.

#

I think I should also read the GC code to understand better how it does the mark/sweep

shadow osprey
#

conversly, how does it know to ... not look at the pointers at all

#

because as soon as I use any *T returned, maybe put it in a go managed struct... what happens...

placid solstice
#

I think that is worst to put go managed structs inside the memory allocated by the OS than the inverse, because there will be no guarantees that the GC will keep those pointers alive (in the case it just ignores unknown pointers). In the case of manually managed memory, the programmer has the responsibility of not reusing the arena or freeing it while there are live pointers.

shadow osprey
#

you should check the (other) arena prototypes how they integrate with the runtime to avoid crashes (or not, not sure)

shadow osprey