Well, the thing about the std.mem.Allocator interface (which is what is returned by gpa's allocator function) is that it basically boils down to two fields: ptr: *anyopaque, vtable: *const VTable and of course, vtable is a pointer to a struct that consists of three runtime function pointers named alloc, resize, and free.
The first parameter to each of the aforementioned function pointers are ptr: *anyopaque, and what they end up doing is casting that to a pointer to the implementation type, e.g. to *std.heap.GeneralPurposeAllocator(.{}). Then they do whatever they do to allocate, resize, or free, the specified memory.
So std.mem.Allocator is, in essence, just a very fancy fat pointer to the implementation - and pointers have to point somewhere, like a stack variable declared via var. Alternatively you could heap allocate it, and have it live on the heap, but that's a lot of overhead to just hide one extra variable.