Thursday, December 12, 2024

How is memory organized in Gliimly

Gliimly is a high-performance memory-safe language. A string variable is the actual pointer to a string (whether it's a text or binary). This eliminates at least one extra memory read, making string access as fast as in C. Bytes before the string constitute the ID to a memory table entry, with additional info used by memory-safety mechanisms:
  • Length (in bytes) of the string,
  • "Ref count" (Reference count), stating how many Gliimly variables point to string,
  • Status is used to describe string, such as whether it's scope is process-wide, if it's a string literal etc,
  • "Next free" points to the next available string block (if this one was freed too),
  • "Data ptr" points back to the string, which is used to speed up access.
Memory is always null-terminated, regardless of whether it's text or binary. Here's what that looks like in a picture:


Each memory block (ID+string+trailing null) is a memory allocated by standard C'd memory allocation, while memory table is a continuous block that's frequently cached to produce fast access to string's properties.

Gliimly performs memory-safety check only at the entrance of a statement, meaning at input and output points (if needed). The actual implementation of any Gliimly statement does not use memory safety internally, because each is implemented in C as a memory safe algorithm to begin with. Because vast majority (probably close to 100%) of the functionality and computation happens inside statements, the actual cost of memory safety is very small.

This is in contrast to general purpose memory-safe languages where libraries, modules, methods etc. are implemented in the memory-safe language and the entire implementation is subject to memory-safe instrumentation and/or other methods, such as bounds checking etc. It means that inherently such languages will perform more work doing such safe-memory checks and likely experience lower performance.

Finally, by default memory is not deallocated immediately after it's out of scope. Rather, the freeing happens when a request is complete, because the request is really the "unit" of work in a web-service based language like Gliimly. However, if your available memory is very low to begin with, you can use "--optimize-memory" flag when compiling your application with gg tool; this will free memory as soon as it's out of scope. Note that this option is not default for a few reasons: the overall performance is better when memory is released in a single go at the end of the request, and more frequent memory checks slow down the performance; hence use this option sparingly and only when necessary.