Custom memory allocator

Hi,

I noticed that glfw uses calloc and free for memory management. I’d like to be able to use custom allocators, to be able to track memory better. I started making some changes to the GLFW source, but I wanted to know if this is something that I should make a PR of? It feels like something that a modern game library should support :slight_smile:

Here’s my proposed solution:

GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share, GLFWallocator* allocator);

Passing in NULL uses calloc and free as normal, otherwise it uses the allocator’s callbacks. It looks like this:

/*! @brief The function pointer type for memory allocation callbacks.
 *
 *  This is the function pointer type for memory allocation callbacks.
 *  A memory allocation callback function has the following signature:
 *  @code
 *  void function_name(void* userdata, int size)
 *  @endcode
 *
 *  @param[in] userdata Any userdata needed to track the allocation.
 *  @param[in] size The size of the allocation.
 *
 *  @sa @ref GLFWallocator
 *
 *  @ingroup memory
 */
typedef void* (* GLFWallocfun)(void*,int);

/*! @brief The function pointer type for memory deallocation callbacks.
 *
 *  This is the function pointer type for memory deallocation callbacks.
 *  A memory deallocation callback function has the following signature:
 *  @code
 *  void function_name(void* userdata, void* pointer)
 *  @endcode
 *
 *  @param[in] userdata Any userdata needed to track the allocation.
 *  @param[in] pointer The pointer to the memory that should be deallocated.
 *
 *  @sa @ref GLFWallocator
 *
 *  @ingroup memory
 */
typedef void (* GLFWdeallocfun)(void*,void*);

/*! @brief Custom allocator.
 *
 *  This allows users to manage memory in a custom fashion.
 *
 *  @ingroup memory
 */
typedef struct GLFWallocator
{
    /*! The allocation function.
     */
    GLFWallocfun allocfun;
    /*! The deallocation function.
     */
    GLFWdeallocfun deallocfun;
    
    /*! The allocator userdata used for tracking memory.
     */
    void* userdata;
} GLFWallocator;

In addition to window management, there are a few other places that use calloc/free that I’ll need to fix.

I agree that it would be good to support custom allocators, but don’t think that modifying the create window function this way is necessarily the best API choice. IMO it should be settable earlier in the init phase so that the user’s allocators can be used throughout, not just for window creation. Any reason not to have it as a compile-time option e.g. a preprocessor definition?

Ah, so store it in GLFWLibrary instead? Sure, I hadn’t seen that. Would be nice to not have to modify the APIs :slight_smile:

As for compile time option, you mean so that it doesn’t have to do this?

if (allocator == NULL) {
    window = (_GLFWwindow*)calloc(1, sizeof(_GLFWwindow));
}
else {
    window = (_GLFWwindow*)allocator->callocfun(allocator->userdata, 1, sizeof(_GLFWwindow));
}

Sure, but… I think I would recommend having just a default allocator instead in glfw that simply calls calloc/free. Having compile time options complicates build setups and there’s no immediate gain to not always having the option IMHO.

You shouldn’t need to wrap every allocation with an if as GLFW could initialise the allocation pointers to standard library calloc and free.

Rather than provide the allocation structure at window creation time I think a glfwSetCustomAllocator() function would be the better approach, with a way to reset it (perhaps if a pointer is null the standard allocation is used).

Documentation should note that the allocation function should zero initialise the memory, as I think GLFW uses calloc throughout.

I forgot to add that GLFW uses very little memory itself, most of the memory you observe being allocated when you create a window is allocated by the driver and OS, and GLFW has no way to track that.

Yep, that all makes sense. :slight_smile:

And yeah, I’m not exactly worried about GLFW memory usage, it’s more of a neatness issue :slight_smile:

GLFW had this for almost a year during 3.0 development but it got cut before release.

Ah! Glad to see someone else was thinking along the same lines. :slight_smile: For me, it’s crucial that I can get userdata passed along to the allocator. Otherwise it looks pretty similar. What do you think is best, shall I leave a comment on your commit (is there a PR somewhere?) or should I submit a PR with my changes? It’s not 100% done yet but only adds allocator support, nothing specifically threading related.