{"id":13514854,"url":"https://github.com/nxrighthere/Smmalloc-CSharp","last_synced_at":"2025-03-31T03:31:34.334Z","repository":{"id":43924208,"uuid":"158775201","full_name":"nxrighthere/Smmalloc-CSharp","owner":"nxrighthere","description":"Blazing fast memory allocator designed for video games meets .NET","archived":false,"fork":false,"pushed_at":"2022-03-13T12:02:34.000Z","size":65,"stargazers_count":163,"open_issues_count":0,"forks_count":11,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-11-01T18:37:58.962Z","etag":null,"topics":["dotnet","gamedev","high-performance","interop","memory-allocator","multi-threading"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nxrighthere.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-11-23T03:14:01.000Z","updated_at":"2024-10-17T18:30:45.000Z","dependencies_parsed_at":"2022-08-12T10:52:00.229Z","dependency_job_id":null,"html_url":"https://github.com/nxrighthere/Smmalloc-CSharp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxrighthere%2FSmmalloc-CSharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxrighthere%2FSmmalloc-CSharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxrighthere%2FSmmalloc-CSharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxrighthere%2FSmmalloc-CSharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nxrighthere","download_url":"https://codeload.github.com/nxrighthere/Smmalloc-CSharp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246413377,"owners_count":20773053,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotnet","gamedev","high-performance","interop","memory-allocator","multi-threading"],"created_at":"2024-08-01T05:01:02.734Z","updated_at":"2025-03-31T03:31:29.324Z","avatar_url":"https://github.com/nxrighthere.png","language":"C++","readme":"\u003cp align=\"center\"\u003e \n  \u003cimg src=\"https://i.imgur.com/7XvtEWf.png\" alt=\"alt logo\"\u003e\n\u003c/p\u003e\n\nThis is an improved version of [smmalloc](https://github.com/SergeyMakeev/smmalloc) a [fast and efficient](https://github.com/SergeyMakeev/smmalloc#features) memory allocator designed to handle many small allocations/deallocations in heavy multi-threaded scenarios. The allocator created for usage in applications where the performance is critical such as video games.\n\nUsing smmalloc allocator in the .NET environment helps to minimize GC pressure for allocating buffers and avoid using lock-based pools in multi-threaded systems. Modern .NET features such as [`Span\u003cT\u003e`](https://docs.microsoft.com/en-us/dotnet/api/system.span-1) greatly works in tandem with smmalloc and allows conveniently manage data in native memory blocks.\n\nBuilding\n--------\nTo build the native library appropriate software is required:\n\nFor desktop platforms [CMake](https://cmake.org/download/) with GNU Make or Visual Studio.\n\nA managed assembly can be built using any available compiling platform that supports C# 3.0 or higher.\n\nUsage\n--------\n##### Create a new smmalloc instance\n```c#\n// 8 buckets, 16 MB each, 128 bytes maximum allocation size\nSmmallocInstance smmalloc = new SmmallocInstance(8, 16 * 1024 * 1024);\n```\n\n##### Destroy the smmalloc instance and free allocated memory\n```c#\nsmmalloc.Dispose();\n```\n\n##### Create thread cache for a current thread\n```c#\n// 4 KB of thread cache for each bucket, hot warmup\nsmmalloc.CreateThreadCache(4 * 1024, CacheWarmupOptions.Hot);\n```\n\n##### Destroy thread cache for a current thread\n```c#\nsmmalloc.DestroyThreadCache();\n```\n\n##### Allocate memory block\n```c#\n// 64 bytes of a memory block\nIntPtr memory = smmalloc.Malloc(64);\n```\n\n##### Release memory block\n```c#\nsmmalloc.Free(memory);\n```\n\n##### Work with batches of memory blocks\n```c#\nIntPtr[] batch = new IntPtr[32];\n\n// Allocate a batch of memory\nfor (int i = 0; i \u003c batch.Length; i++) {\n\tbatch[i] = smmalloc.Malloc(64);\n}\n\n// Release the whole batch\nsmmalloc.Free(batch);\n```\n\n##### Write data to memory block\n```c#\n// Using Marshal\nbyte data = 0;\n\nfor (int i = 0; i \u003c smmalloc.Size(memory); i++) {\n\tMarshal.WriteByte(memory, i, data++);\n}\n\n// Using Span\nSpan\u003cbyte\u003e buffer;\n\nunsafe {\n\tbuffer = new Span\u003cbyte\u003e((byte*)memory, smmalloc.Size(memory));\n}\n\nbyte data = 0;\n\nfor (int i = 0; i \u003c buffer.Length; i++) {\n\tbuffer[i] = data++;\n}\n```\n\n##### Read data from memory block\n```c#\n// Using Marshal\nint sum = 0;\n\nfor (int i = 0; i \u003c smmalloc.Size(memory); i++) {\n\tsum += Marshal.ReadByte(memory, i);\n}\n\n// Using Span\nint sum = 0;\n\nforeach (var value in buffer) {\n\tsum += value;\n}\n```\n\n##### Hardware accelerated operations\n```c#\n// Xor using Vector and Span\nif (Vector.IsHardwareAccelerated) {\n\tSpan\u003cVector\u003cbyte\u003e\u003e bufferVector = MemoryMarshal.Cast\u003cbyte, Vector\u003cbyte\u003e\u003e(buffer);\n\tSpan\u003cVector\u003cbyte\u003e\u003e xorVector = MemoryMarshal.Cast\u003cbyte, Vector\u003cbyte\u003e\u003e(xor);\n\n\tfor (int i = 0; i \u003c bufferVector.Length; i++) {\n\t\tbufferVector[i] ^= xorVector[i];\n\t}\n}\n```\n\n##### Copy data using memory block\n```c#\n// Using Marshal\nbyte[] data = new byte[64];\n\n// Copy from native memory\nMarshal.Copy(memory, data, 0, 64);\n\n// Copy to native memory\nMarshal.Copy(data, 0, memory, 64);\n\n// Using Buffer\nunsafe {\n\t// Copy from native memory\n\tfixed (byte* destination = \u0026data[0]) {\n\t\tBuffer.MemoryCopy((byte*)memory, destination, 64, 64);\n\t}\n\n\t// Copy to native memory\n\tfixed (byte* source = \u0026data[0]) {\n\t\tBuffer.MemoryCopy(source, (byte*)memory, 64, 64);\n\t}\n}\n```\n\n##### Custom data structures\n```c#\n// Define a custom structure\nstruct Entity {\n\tpublic uint id;\n\tpublic byte health;\n\tpublic byte state;\n}\n\nint entitySize = Marshal.SizeOf(typeof(Entity));\nint entityCount = 10;\n\n// Allocate memory block\nIntPtr memory = smmalloc.Malloc(entitySize * entityCount);\n\n// Create Span using native memory block\nSpan\u003cEntity\u003e entities;\n\nunsafe {\n\tentities = new Span\u003cEntity\u003e((void*)memory, entityCount);\n}\n\n// Do some stuff\nuint id = 1;\n\nfor (int i = 0; i \u003c entities.Length; i++) {\n\tentities[i].id = id++;\n\tentities[i].health = (byte)(new Random().Next(1, 100));\n\tentities[i].state = (byte)(new Random().Next(1, 255));\n}\n\n// Release memory block\nsmmalloc.Free(memory);\n```\n\nAPI reference\n--------\n### Enumerations\n#### CacheWarmupOptions\nDefinitions of warmup options for `CreateThreadCache()` function:\n\n`CacheWarmupOptions.Cold` warmup not performed for cache elements.\n\n`CacheWarmupOptions.Warm` warmup performed for half of the cache elements.\n\n`CacheWarmupOptions.Hot` warmup performed for all cache elements.\n\n### Classes\nA single low-level disposable class is used to work with smmalloc. \n\n#### SmmallocInstance\nContains a managed pointer to the smmalloc instance.\n\n##### Constructors\n`SmmallocInstance(uint bucketsCount, int bucketSize)` creates allocator instance with a memory pool. Size of memory blocks in each bucket increases with a count of buckets. The bucket size parameter sets an initial size of a pooled memory in bytes.\n\n##### Methods\n`SmmallocInstance.Dispose()` destroys the smmalloc instance and frees allocated memory.\n\n`SmmallocInstance.CreateThreadCache(int cacheSize, CacheWarmupOptions warmupOption)` creates thread cache for fast memory allocations within a thread. The warmup option sets pre-allocation degree of cache elements.\n\n`SmmallocInstance.DestroyThreadCache()` destroys the thread cache. Should be called before the end of the thread's life cycle.\n\n`SmmallocInstance.Malloc(int bytesCount, int alignment)` allocates aligned memory block. Allocation size depends on buckets count multiplied by 16, so the minimum allocation size is 16 bytes. Maximum allocation size using two buckets in a smmalloc instance will be 32 bytes, for three buckets 48 bytes, for four 64 bytes, and so on. The alignment parameter is optional. Returns pointer to a memory block. Returns a pointer to an allocated memory block.\n\n`SmmallocInstance.Free(IntPtr memory)` frees memory block. A managed array or pointer to pointers with length can be used instead of a pointer to memory block to free a batch of memory.\n\n`SmmallocInstance.Realloc(IntPtr memory, int bytesCount, int alignment)` reallocates memory block. The alignment parameter is optional. Returns a pointer to a reallocated memory block.\n\n`SmmallocInstance.Size(IntPtr memory)` gets usable memory size. Returns size in bytes.\n\n`SmmallocInstance.Bucket(IntPtr memory)` gets bucket index of a memory block. Returns placement index.\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnxrighthere%2FSmmalloc-CSharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnxrighthere%2FSmmalloc-CSharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnxrighthere%2FSmmalloc-CSharp/lists"}