{"id":37537192,"url":"https://github.com/nazarovsa/csharp-zero-allocation","last_synced_at":"2026-01-16T08:40:59.452Z","repository":{"id":44369079,"uuid":"480555783","full_name":"nazarovsa/csharp-zero-allocation","owner":"nazarovsa","description":"Contains materials about memory optimization and zero-allocation samples.","archived":false,"fork":false,"pushed_at":"2024-02-05T12:11:34.000Z","size":2714,"stargazers_count":38,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2024-02-05T13:29:38.953Z","etag":null,"topics":["csharp","memory-optimization","zero-allocation"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nazarovsa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-04-11T21:21:31.000Z","updated_at":"2024-02-05T13:29:39.928Z","dependencies_parsed_at":"2023-12-05T16:37:14.700Z","dependency_job_id":null,"html_url":"https://github.com/nazarovsa/csharp-zero-allocation","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nazarovsa/csharp-zero-allocation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nazarovsa%2Fcsharp-zero-allocation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nazarovsa%2Fcsharp-zero-allocation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nazarovsa%2Fcsharp-zero-allocation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nazarovsa%2Fcsharp-zero-allocation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nazarovsa","download_url":"https://codeload.github.com/nazarovsa/csharp-zero-allocation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nazarovsa%2Fcsharp-zero-allocation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["csharp","memory-optimization","zero-allocation"],"created_at":"2026-01-16T08:40:58.860Z","updated_at":"2026-01-16T08:40:59.443Z","avatar_url":"https://github.com/nazarovsa.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# C# Zero Allocation\n\nRepository contains materials collected by me about memory allocation and optimization. \nAt the end of README.md you can find links to original sources.  \n\n**All rights for original materials belong to the authors.**\n\n⭐️ *If you find the repository usefull, give it a star!*\n\n## Memory problems in our algorithms\n\nReasons why we have problems with memory:\n- Incorrect memory allocation. (Create objects in loops, etc.)\n- Weak knowledge about how the .net platform operates. (String is immutable, struct types are copied on pass, etc.)\n- Weak knowledge about language features.\n\n## Our instruments for optimization\n\nOur main principle is \"Allocate as little memory as possible\". But sometimes it is not enough.\nIt may seem strange, but in some cases, we can avoid allocating memory at all if we know the advanced features of a language.\n\nLet's start with some interesting facts about the `struct` type and then look closer to other instruments for optimization.\n\n### Structures and their vagaries (~17 minutes to read)\n_Much of the sample code in this section uses features added in **C# 7.2**. \nTo use those features, make sure your project isn't configured to use an earlier version._ \n\nAs we know, `struct` is a value type.\nOne advantage to using value types is that they often avoid heap allocations. \nThe disadvantage is that they're copied by value. \nThis trade-off makes it harder to optimize algorithms that operate on large amounts of data. \nThe language features highlighted in this section provide mechanisms that enable safe efficient code using references to value types. \nUse these features wisely to minimize both allocations and copy operations.\n\nThe section also explains some low-level optimizations that are advisable when you've run a profiler and have identified bottlenecks:\n- Use the `in` parameter modifier.\n- Use `ref readonly return` statements.\n- Use `ref struct` types.\n- Use `nint` and `nuint` types.  \n\nThese techniques balance two competing goals:\n- **Minimize allocations on the heap**: variables that are reference types hold a reference to a location in memory and are allocated on the managed heap. Only the reference is copied when a reference type is passed as an argument to a method or returned from a method. Each new object requires a new allocation, and later must be reclaimed. Garbage collection takes time.\n- **Minimize the copying of values**: variables that are value types directly contain their value, and the value is typically copied when passed to a method or returned from a method. This behavior includes copying the value of this when calling iterators and async instance methods of structs. The copy operation takes time, depending on the size of the type.\n\nThis section uses the following example concept of the 3D-point structure to explain its recommendations:\n```csharp\npublic struct Point3D\n{\n    public double X;\n    public double Y;\n    public double Z;\n}\n```\nDifferent examples use different implementations of this concept.\n\n#### Declare immutable structs as readonly\n\nDeclare a `readonly struct` to indicate that a type is **immutable**. \nThe readonly modifier informs the compiler that your intent is to create an immutable type. \n\nThe compiler enforces that design decision with the following rules:\n- All field members must be read-only.\n- All properties must be read-only, including auto-implemented properties.\n \nThese two rules are sufficient to ensure that no member of a `readonly struct` modifies the state of that struct. \nThe struct is immutable. The Point3D structure could be defined as an immutable struct as shown in the following example:\n\n```csharp\nreadonly public struct ReadonlyPoint3D\n{\n    public ReadonlyPoint3D(double x, double y, double z)\n    {\n        this.X = x;\n        this.Y = y;\n        this.Z = z;\n    }\n\n    public double X { get; }\n    public double Y { get; }\n    public double Z { get; }\n}\n```\n\nFollow this recommendation whenever your design intent is to create an immutable value type. \nAny performance improvements are an added benefit. The `readonly struct` keywords clearly express your design intent.\n\n#### Declare readonly members for mutable structs\n\nIn C# 8.0 and later, when a struct type is mutable, declare members that don't modify state as [readonly members](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#readonly-instance-members).\nConsider a different application that needs a 3D point structure, but must support mutability. \nThe following version of the 3D point structure adds the readonly modifier only to those members that don't modify the structure. \nFollow this example when your design must support modifications to the struct by some members, but you still want the benefits of enforcing readonly on some members:\n\n```csharp\npublic struct Point3D\n{\n    public Point3D(double x, double y, double z)\n    {\n        _x = x;\n        _y = y;\n        _z = z;\n    }\n\n    private double _x;\n    public double X\n    {\n        readonly get =\u003e _x;\n        set =\u003e _x = value;\n    }\n\n    private double _y;\n    public double Y\n    {\n        readonly get =\u003e _y;\n        set =\u003e _y = value;\n    }\n\n    private double _z;\n    public double Z\n    {\n        readonly get =\u003e _z;\n        set =\u003e _z = value;\n    }\n\n    public readonly double Distance =\u003e Math.Sqrt(X * X + Y * Y + Z * Z);\n\n    public readonly override string ToString() =\u003e $\"{X}, {Y}, {Z}\";\n}\n```\n\nThe preceding sample shows many of the locations where you can apply the `readonly` modifier: methods, properties, and property accessors. \nIf you use auto-implemented properties, the compiler adds the `readonly` modifier to the `get` accessor for read-write properties. \nThe compiler adds the `readonly` modifier to the auto-implemented property declarations for properties with only a `get` accessor.\n\nAdding the `readonly` modifier to members that don't mutate state provides two related benefits. First, the compiler enforces your intent. \nThat member can't mutate the struct's state. Second, the compiler won't create [defensive copies](https://github.com/nazarovsa/csharp-zero-allocation#avoid-defensive-copies) of `in` parameters when accessing a `readonly` member. \nThe compiler can make this optimization safely because it guarantees that the `struct` is not modified by a `readonly` member.\n\n#### Use `ref readonly return` statements\n\nUse a `ref readonly return` when both of the following conditions are true:\n- The return value is a `struct` larger than [IntPtr.Size](https://docs.microsoft.com/en-us/dotnet/api/system.intptr.size?view=net-6.0#system-intptr-size).\n- The storage lifetime is greater than the method returning the value.\n\nYou can return values by reference when the value being returned isn't local to the returning method. \nReturning by reference means that only the reference is copied, not the structure. \nIn the following example, the Origin property can't use a ref return because the value being returned is a local variable:\n```csharp\npublic Point3D Origin =\u003e new Point3D(0,0,0);\n```\n\nHowever, the following property definition can be returned by reference because the returned value is a static member:\n```csharp\npublic struct Point3D\n{\n    private static Point3D origin = new Point3D(0,0,0);\n\n    // Dangerous! returning a mutable reference to internal storage\n    public ref Point3D Origin =\u003e ref origin;\n\n    // other members removed for space\n}\n```\n\nYou don't want callers modifying the origin, so you should return the value by ref readonly:\n```csharp\npublic struct Point3D\n{\n    private static Point3D origin = new Point3D(0,0,0);\n\n    public static ref readonly Point3D Origin =\u003e ref origin;\n\n    // other members removed for space\n}\n```\n\nReturning `ref readonly enables` you to save copying larger structures and preserve the immutability of your internal data members.\nAt the call site, callers make the choice to use the `Origin` property as a `ref readonly` or as a value:\n\n```csharp\nvar originValue = Point3D.Origin;\nref readonly var originReference = ref Point3D.Origin;\n```\n\nThe first assignment in the preceding code makes a copy of the `Origin` constant and assigns that copy. \nThe second assigns a reference. \nNotice that the `readonly` modifier must be part of the declaration of the variable. The reference to which it refers can't be modified. Attempts to do so result in a compile-time error.\n\nThe `readonly` modifier is required on the declaration of `originReference`.\n\nThe compiler enforces that the caller can't modify the reference. \nAttempts to assign the value directly generate a compile-time error. \nIn other cases, the compiler allocates a defensive copy unless it can safely use the readonly reference. \nStatic analysis rules determine if the struct could be modified. \nThe compiler doesn't create a defensive copy when the struct is a `readonly struct` or the member is a `readonly` member of the struct. \nDefensive copies aren't needed to pass the struct as an `in` argument.\n\n#### Use the in parameter modifier\n\nThe following sections explain what the in modifier does, how to use it, and when to use it for performance optimization.\n\n##### The out, ref, and in keywords\n\nThe `in` keyword complements the `ref` and `out` keywords to pass arguments by reference. \nThe `in` keyword specifies that the argument is passed by reference, but the called method doesn't modify the value. \nThe `in` modifier can be applied to any member that takes parameters, such as methods, delegates, lambdas, local functions, indexers, and operators.\n\nWith the addition of the `in` keyword, C# provides a full vocabulary to express your design intent. Value types are copied when passed to a called method when you don't specify any of the following modifiers in the method signature. Each of these modifiers specifies that a variable is passed by reference, avoiding the copy. Each modifier expresses a different intent:\n- `out`: This method sets the value of the argument used as this parameter.\n- `ref`: This method may modify the value of the argument used as this parameter.\n- `in`: This method doesn't modify the value of the argument used as this parameter.\n\nAdd the `in` modifier to pass an argument by reference and declare your design intent to pass arguments by reference to avoid unnecessary copying. \nYou don't intend to modify the object used as that argument.\n\nThe `in` modifier complements `out` and `ref` in other ways as well. \nYou can't create overloads of a method that differ only in the presence of `in`, `out`, or `ref`. \nThese new rules extend the same behavior that had always been defined for `out` and `ref` parameters. \nLike the `out` and `ref` modifiers, value types aren't boxed because the `in` modifier is applied. \nAnother feature of `in` parameters is that you can use literal values or constants for the argument to an `in` parameter.\n\nThe `in` modifier can also be used with reference types or numeric values. However, the benefits in those cases are minimal, if any.\n\nThere are several ways in which the compiler enforces the read-only nature of an `in` argument. \nFirst of all, the called method can't directly assign to an `in` parameter. \nIt can't directly assign to any field of an `in` parameter when that value is a `struct` type. \nIn addition, you can't pass an `in` parameter to any method using the `ref` or `out` modifier. \nThese rules apply to any field of an `in` parameter, provided the field is a `struct` type and the parameter is also a `struct` type. \nIn fact, these rules apply for multiple layers of member access provided the types at all levels of member access are `structs`. \nThe compiler enforces that `struct` types passed as `in` arguments and their `struct` members are read-only variables when used as arguments to other methods.\n\n##### Use in parameters for large structs\n\nYou can apply the `in` modifier to any `readonly struct` parameter, \nbut this practice is likely to improve performance only for value types that are substantially larger than [IntPtr.Size](https://docs.microsoft.com/en-us/dotnet/api/system.intptr.size?view=net-6.0#system-intptr-size). \nFor simple types (such as `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal` and `bool`, and `enum` types), \nany potential performance gains are minimal. \nSome simple types, such as `decimal` at 16 bytes in size, \nare larger than either 4-byte or 8-byte references but not by enough to make a measurable difference in performance in most scenarios. \nAnd performance may degrade by using pass-by-reference for types smaller than [IntPtr.Size](https://docs.microsoft.com/en-us/dotnet/api/system.intptr.size?view=net-6.0#system-intptr-size).\n\nThe following code shows an example of a method that calculates the distance between two points in 3D space.\n\n```csharp\nprivate static double CalculateDistance(in Point3D point1, in Point3D point2)\n{\n    double xDifference = point1.X - point2.X;\n    double yDifference = point1.Y - point2.Y;\n    double zDifference = point1.Z - point2.Z;\n\n    return Math.Sqrt(\n        xDifference * xDifference + \n        yDifference * yDifference + \n        zDifference * zDifference);\n}\n```\n\nThe arguments are two structures that each contain three doubles. \nA double is 8 bytes, so each argument is 24 bytes. \nBy specifying the in modifier, you pass a 4-byte or 8-byte reference to those arguments, depending on the architecture of the machine. \nThe difference in size is small, but it can add up when your application calls this method in a tight loop using many different values.\n\nHowever, the impact of any low-level optimizations like using the `in` modifier should be measured to validate a performance benefit. \nFor example, you might think that using in on a `Guid` parameter would be beneficial. The `Guid` type is 16 bytes in size, twice the size of an 8-byte reference. \nBut such a small difference isn't likely to result in a measurable performance benefit unless it's in a method that's in a time critical hot path for your application.\n\n##### Optional use of in at call site\n\nUnlike a `ref` or `out` parameter, you don't need to apply the `in` modifier at the call site. \nThe following code shows two examples of calling the `CalculateDistance` method. \nThe first uses two local variables passed by reference. \nThe second includes a temporary variable created as part of the method call.\n```csharp\nvar distance = CalculateDistance(pt1, pt2);\nvar fromOrigin = CalculateDistance(pt1, new Point3D());\n```\n\nOmitting the `in` modifier at the call site informs the compiler that it's allowed to make a copy of the argument for any of the following reasons:\n- There exists an implicit conversion but not an identity conversion from the argument type to the parameter type.\n- The argument is an expression but doesn't have a known storage variable.\n- An overload exists that differs by the presence or absence of `in`. In that case, the by value overload is a better match.\n\nThese rules are useful as you update existing code to use read-only reference arguments. \nInside the called method, you can call any instance method that uses by-value parameters. \nIn those instances, a copy of the `in` parameter is created.\n\nBecause the compiler may create a temporary variable for any `in` parameter, \nyou can also specify default values for any `in` parameter. \nThe following code specifies the origin (point 0,0,0) as the default value for the second point:\n```csharp\nprivate static double CalculateDistance2(in Point3D point1, in Point3D point2 = default)\n{\n    double xDifference = point1.X - point2.X;\n    double yDifference = point1.Y - point2.Y;\n    double zDifference = point1.Z - point2.Z;\n\n    return Math.Sqrt(xDifference * xDifference + \n        yDifference * yDifference + \n        zDifference * zDifference);\n}\n```\n\nTo force the compiler to pass read-only arguments by reference, \nspecify the `in` modifier on the arguments at the call site, as shown in the following code:\n```csharp\ndistance = CalculateDistance(in pt1, in pt2);\ndistance = CalculateDistance(in pt1, new Point3D());\ndistance = CalculateDistance(pt1, in Point3D.Origin);\n```\nThis behavior makes it easier to adopt `in` parameters over time in large codebases where performance gains are possible. \nYou add the `in` modifier to method signatures first. \nThen you can add the `in` modifier at call sites\nand create `readonly struct` types to enable the compiler to avoid creating defensive copies of `in` parameters in more locations.\n\n##### Avoid defensive copies\n\nPass a `struct` as the argument for an `in` parameter only if it's declared with the `readonly` modifier or the method accesses only `readonly` members of the struct. \nOtherwise, the compiler must create _defensive copies_ in many situations to ensure that arguments are not mutated. \nConsider the following example that calculates the distance of a 3D point from the origin:\n```csharp\nprivate static double CalculateDistance(in Point3D point1, in Point3D point2)\n{\n    double xDifference = point1.X - point2.X;\n    double yDifference = point1.Y - point2.Y;\n    double zDifference = point1.Z - point2.Z;\n\n    return Math.Sqrt(xDifference * xDifference + \n        yDifference * yDifference + \n        zDifference * zDifference);\n}\n```\n\nThe `Point3D` structure is not a read-only struct. \nThere are six different property access calls in the body of this method. \nOn first examination, you may think these accesses are safe. \nAfter all, a `get` accessor shouldn't modify the state of the object. \nBut there's no language rule that enforces that. \nIt's only a common convention. \nAny type could implement a `get` accessor that modified the internal state.\n\nWithout some language guarantee, the compiler must create a temporary copy of the argument before calling any member not marked with the `readonly` modifier. \nThe temporary storage is created on the stack, the values of the argument are copied to the temporary storage, \nand the value is copied to the stack for each member access as the `this` argument. \nIn many situations, these copies harm performance enough that pass-by-value is faster \nthan pass-by-read-only-reference when the argument type isn't a `readonly struct` and the method calls members that aren't marked `readonly`. \nIf you mark all methods that don't modify the struct state as `readonly`, \nthe compiler can safely determine that the struct state isn't modified, and a defensive copy is not needed.\n\nIf the distance calculation uses the immutable struct, `ReadonlyPoint3D`, temporary objects aren't needed:\n```csharp\nprivate static double CalculateDistance3(\n    in ReadonlyPoint3D point1, \n    in ReadonlyPoint3D point2 = default)\n{\n    double xDifference = point1.X - point2.X;\n    double yDifference = point1.Y - point2.Y;\n    double zDifference = point1.Z - point2.Z;\n\n    return Math.Sqrt(xDifference * xDifference + \n        yDifference * yDifference + \n        zDifference * zDifference);\n}\n```\n\nThe compiler generates more efficient code when you call members of a `readonly struct`. \nThe `this` reference, instead of a copy of the receiver, is always an `in` parameter passed by reference to the member method. \nThis optimization saves copying when you use a `readonly struct` as an `in` argument.\n\nDon't pass a nullable value type as an `in` argument. \nThe `Nullable\u003cT\u003e` type isn't declared as a read-only struct. \nThat means the compiler must generate defensive copies for any nullable value type argument passed to a method using the `in` modifier on the parameter declaration.\n\nYou can see an example program that demonstrates the performance differences using BenchmarkDotNet in dotnet [samples repository](https://github.com/dotnet/samples/tree/main/csharp/safe-efficient-code/benchmark) on GitHub. \nIt compares passing a mutable struct by value and by reference with passing an immutable struct by value and by reference. The use of the immutable struct and pass by reference is fastest.\n\n#### Use ref struct types\n\nUse a ref struct or a `readonly ref struct`, such as `Span\u003cT\u003e` or `ReadOnlySpan\u003cT\u003e`, \nto work with blocks of memory as a sequence of bytes. \nThe memory used by the span is constrained to a single stack frame. \nThis restriction enables the compiler to make several optimizations. \nThe primary motivation for this feature was `Span\u003cT\u003e` and related structures. \nYou'll achieve performance improvements from these enhancements by using new and updated .NET APIs that make use of the Span\u003cT\u003e type.\n\nDeclaring a struct as `readonly ref` combines the benefits and restrictions of `ref struct` and `readonly struct` declarations. \nThe memory used by the readonly span is restricted to a single stack frame, \nand the memory used by the readonly span can't be modified.\n\nYou may have similar requirements working with memory created using `stackalloc` or when using memory from interop APIs. \nYou can define your own `ref struct` types for those needs.\n\n#### Use nint and nuint types\n\n[Native-sized integer types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nint-nuint) are 32-bit integers in a 32-bit process or 64-bit integers in a 64-bit process. \nUse them for interop scenarios, low-level libraries, and to optimize performance in scenarios where integer math is used extensively.\n\n#### Conclusions\n\nUsing value types minimizes the number of allocation operations:\n- Storage for value types is stack-allocated for local variables and method arguments.\n- Storage for value types that are members of other objects is allocated as part of that object, not as a separate allocation.\n- Storage for value type return values is stack allocated.\n\nContrast that with reference types in those same situations:\n- Storage for reference types is heap allocated for local variables and method arguments. The reference is stored on the stack.\n- Storage for reference types that are members of other objects are separately allocated on the heap. The containing object stores the reference.\n- Storage for reference type return values is heap allocated. The reference to that storage is stored on the stack.\n\nMinimizing allocations comes with tradeoffs. You copy more memory when the size of the struct is larger than the size of a reference. A reference is typically 64 bits or 32 bits, and depends on the target machine CPU.\n\nThese tradeoffs generally have minimal performance impact. However, for large structs or larger collections, the performance impact increases. The impact can be large in tight loops and hot paths for programs.\n\nThese enhancements to the C# language are designed for performance critical algorithms where minimizing memory allocations is a major factor in achieving the necessary performance. You may find that you don't often use these features in the code you write. However, these enhancements have been adopted throughout .NET. As more APIs make use of these features, you'll see the performance of your applications improve.\n\n### `Span\u003cT\u003e`, `ReadOnlySpan\u003cT\u003e`, stackalloc\n\n#### `Span\u003cT\u003e`\n\nProvides a type- and memory-safe representation of a contiguous region of arbitrary memory.\n\n**`Span\u003cT\u003e` is a ref struct that is allocated on the stack rather than on the managed heap.** Ref struct types have a number of **restrictions** to ensure that they cannot be promoted to the managed heap:  \n- They can't be boxed\n- They can't be assigned to variables of type `Object`, dynamic or to any interface type\n- They can't be fields in a reference type\n- They can't be used across await and yield boundaries. \n\nIn addition, calls to two methods, `Equals(Object)` and GetHashCode, throw a `NotSupportedException`.\n\nA `Span\u003cT\u003e` represents a contiguous region of arbitrary memory. A `Span\u003cT\u003e` instance is often used to hold the elements of an array or a portion of an array. Unlike an array, however, a `Span\u003cT\u003e` instance can point to managed memory, native memory, or memory managed on the stack.\n\n##### `Span\u003cT\u003e` and arrays\n\nWhen it wraps an array, `Span\u003cT\u003e` can wrap an entire array, as it did in the examples in the `Span\u003cT\u003e` and memory section. Because it supports slicing, `Span\u003cT\u003e` can also point to any contiguous range within the array.\nThe following example creates a slice of the middle five elements of a 10-element integer array. Note that the code doubles the values of each integer in the slice. As the output shows, the changes made by the span are reflected in the values of the array.\n\n```csharp\nusing System;\n\nvar array = new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };\nvar slice = new Span\u003cint\u003e(array, 2, 5);\nfor (int ctr = 0; ctr \u003c slice.Length; ctr++)\n    slice[ctr] *= 2;\n\n// Examine the original array values.\nforeach (var value in array)\n    Console.Write($\"{value}  \");\nConsole.WriteLine();\n\n// The example displays the following output:\n//      2  4  12  16  20  24  28  16  18  20\n```\n\n##### `Span\u003cT\u003e` and slices\n\n`Span\u003cT\u003e` includes two overloads of the `Slice` method that form a slice out of the current span that starts at a specified index. This makes it possible to treat the data in a `Span\u003cT\u003e` as a set of logical chunks that can be processed as needed by portions of a data processing pipeline with minimal performance impact.  \nFor example, since modern server protocols are often text-based, manipulation of strings and substrings is particularly important. In the String class, the major method for extracting substrings is Substring. For data pipelines that rely on extensive string manipulation, its use offers some performance penalties, since it:\n- Creates a new string to hold the substring.\n- Copies a subset of the characters from the original string to the new string.\nThis allocation and copy operation can be eliminated by using either `Span\u003cT\u003e` or `ReadOnlySpan\u003cT\u003e`, as the following example shows:\n\n```csharp\nusing System;\n\nclass Program\n{\n    static void Main()\n    {\n        string contentLength = \"Content-Length: 132\";\n        var length = GetContentLength(contentLength.ToCharArray());\n        Console.WriteLine($\"Content length: \u003clength\u003e\");\n    }\n\n    private static int GetContentLength(ReadOnlySpan\u003cchar\u003e span)\n    {\n        var slice = span.Slice(16);\n        return int.Parse(slice);\n    }\n}\n// Output:\n//      Content length: 132 \n```\n\n#### `ReadOnlySpan\u003cT\u003e`\n\nProvides a type-safe and memory-safe **read-only** representation of a contiguous region of arbitrary memory.\n\n**`ReadOnlySpan\u003cT\u003e` is a ref struct that is allocated on the stack and can never escape to the managed heap.** `ReadOnlySpan\u003cT\u003e` has the same restrictions as `Span\u003cT\u003e`.\nA `ReadOnlySpan\u003cT\u003e` instance is often used to reference the elements of an array or a portion of an array. Unlike an array, however, a `ReadOnlySpan\u003cT\u003e` instance can point to managed memory, native memory, or memory managed on the stack.\n\n#### stackalloc\n\nA `stackalloc` expression allocates a block of memory on the stack. A stack allocated memory block created during the method execution is automatically discarded when that method returns. You cannot explicitly free the memory allocated with `stackalloc`. A stack allocated memory block is not subject to garbage collection and doesn't have to be pinned with a fixed statement.\nYou can assign the result of a stackalloc expression to a variable of one of the following types:\n- Beginning with C# 7.2, System.Span\u003cT\u003e or System.ReadOnlySpan\u003cT\u003e\n- A pointer type, as the following example shows\n\n**The amount of memory available on the stack is limited.** If you allocate too much memory on the stack, a `StackOverflowException` is thrown. To avoid that, follow the rules below:\n- Limit the amount of memory you allocate with stackalloc. For example, if the intended buffer size is below a certain limit, you allocate the memory on the stack; otherwise, use an array of the required length, as the following code shows:\n```csharp\nconst int MaxStackLimit = 1024;\nSpan\u003cbyte\u003e buffer = inputLength \u003c= MaxStackLimit \n    ? stackalloc byte[MaxStackLimit] \n    : new byte[inputLength]; \n```\n- Avoid using `stackalloc` inside loops. Allocate the memory block outside a loop and reuse it inside the loop.\n\n**The content of the newly allocated memory is undefined.** You should initialize it before the use. For example, you can use the `Span\u003cT\u003e.Clear` method that sets all the items to the default value of type T.\n\n### `Memory\u003cT\u003e`, `ReadOnlyMemory\u003cT\u003e`, `IMemoryOwner\u003cT\u003e`\n\n#### `Memory\u003cT\u003e`\nRepresents a contiguous region of memory.\n\nLike `Span\u003cT\u003e`, `Memory\u003cT\u003e` represents a contiguous region of memory. **Unlike `Span\u003cT\u003e`, however, `Memory\u003cT\u003e` is not a ref struct**. This means that **`Memory\u003cT\u003e` can be placed on the managed heap**, whereas `Span\u003cT\u003e` cannot. As a result, the **`Memory\u003cT\u003e` structure does not have the same restrictions as a `Span\u003cT\u003e`** instance. In particular:\n- It can be used as a field in a class.\n- It can be used across await and yield boundaries.\n\nIn addition to `Memory\u003cT\u003e`, you can use `System.ReadOnlyMemory\u003cT\u003e` to represent immutable or read-only memory.\n\n#### `ReadOnlyMemory\u003cT\u003e`\n\nRepresents a contiguous region of memory, similar to ReadOnlySpan\u003cT\u003e. **Unlike `ReadOnlySpan\u003cT\u003e`, it is not a byref-like type**.\n\n#### `IMemoryOwner\u003cT\u003e`\nIdentifies the owner of a block of memory who is responsible for disposing of the underlying memory appropriately.\n\n`IMemoryOwner\u003cT\u003e` can be used to manage rented memory in a right manner. These cases are occuring when you need to pass a memory block through your calls.\n\nThe `IMemoryOwner\u003cT\u003e` interface is used to define the owner responsible for the lifetime management of a `Memory\u003cT\u003e` buffer. An instance of the `IMemoryOwner\u003cT\u003e` interface is returned by the `MemoryPool\u003cT\u003e.Rent` method.\nWhile a buffer can have multiple consumers, it can only have a single owner at any given time. The owner can:\nCreate the buffer either directly or by calling a factory method.\nTransfer ownership to another consumer. In this case, the previous owner should no longer use the buffer.\nDestroy the buffer when it is no longer in use.\nBecause the `IMemoryOwner\u003cT\u003e` object implements the `IDisposable` interface, you should call its `Dispose` method only after the memory buffer is no longer needed and you have destroyed it. You should not dispose of the `IMemoryOwner\u003cT\u003e` object while a reference to its memory is available. This means that the type in which `IMemoryOwner\u003cT\u003e` is declared should not have a `Finalize` method.\n\n### Pooling\n\n#### Object pooling\n\nThe object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a \"pool\" – rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object to the pool rather than destroying it; this can be done manually or automatically.\n\nObject pools are primarily used for performance: in some circumstances, object pools significantly improve performance. Object pools complicate object lifetime, as objects obtained from and returned to a pool are not actually created or destroyed at this time, and thus require care in implementation.\n\n#### Array pooling\n\nArray pooling is similar to object pooling, but you use the pool of arrays instead. C# allows us to use that mechanism via ArrayPool class.\n\nUse arrays from the pool when you need an array of the same length and can’t allocate it on\nthe stack. For example, instead of creating a new array at each method call, use the array\npool.\n\nUse `ArrayPool\u003cT\u003e.Shared.Rent(int minimumLength)` to rent array from the pool.  \nUse `ArrayPool\u003cT\u003e.Shared.Return(T[] array, bool clearArray = false)` to return array into the pool.\n\nInstead of \n\n```csharp\npublic void DoSomeWork()\n{\n    var array = new double[2048];\n    // Do some work\n}\n```\n\nUse \n\n```csharp\npublic void DoSomeWork()\n{\n    var array = ArrayPool\u003cdouble\u003e.Shared.Rent(2048);\n    try\n    {\n        // Do some work\n    }\n    finally\n    {\n        ArrayPool\u003cdouble\u003e.Shared.Return(array);\n    }\n}\n```\n\n#### How pools helps us save memory\n\nObviously, if we are reusing objects or arrays, it allow us to save memory and prevent GC collections. We don't need to create and destroy extra objects anymore, because we taking them from the pool.\n\n## Practice\n\n- [ValueStringBuilder](https://github.com/nazarovsa/csharp-zero-allocation/blob/main/src/ZeroAllocation.Core/ValueStringBuilder.cs)\n- [QueryBuilder](https://github.com/nazarovsa/csharp-zero-allocation/tree/main/src/QueryBuilders.Benchmark) - Benchmarks of building queries by different ways.\n- [ObjectPools](https://github.com/nazarovsa/csharp-zero-allocation/tree/main/src/ObjectPools.Benchmark) - Benchmarks of object pool usage.\n- [GuidTransformer](https://github.com/nazarovsa/csharp-zero-allocation/tree/main/src/GuidTransformer) - Optimization sample of guid to efficient string helper.\n- [Abstract lottery ticket combination generator](https://github.com/nazarovsa/csharp-zero-allocation/tree/main/src/Generation) - Optimization sample of lottery ticket combination generator.\n\n## Sources\n### In English\n\n- [`Span\u003cT\u003e`: docs](https://docs.microsoft.com/en-us/dotnet/api/system.span-1?view=net-6.0)\n- [`ReadOnlySpan\u003cT\u003e`: docs](https://docs.microsoft.com/en-us/dotnet/api/system.readonlyspan-1?view=net-6.0)\n- [`stackalloc`: docs](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/stackalloc)\n- [`Memory\u003cT\u003e`: docs](https://docs.microsoft.com/en-us/dotnet/api/system.memory-1?view=net-6.0)\n- [`IMemoryOwner\u003cT\u003e`: docs](https://docs.microsoft.com/en-us/dotnet/api/system.buffers.imemoryowner-1?view=net-6.0)\n- [Write safe and efficient C# code](https://docs.microsoft.com/en-us/dotnet/csharp/write-safe-efficient-code)\n- [.NET Platform Architecture. Stanislav Sidristij - Memory\u003cT\u003e and Span\u003cT\u003e](https://github.com/sidristij/dotnetbook/blob/master/book/en/MemorySpan.md)\n- [What is Span in C# and why you should be using it](https://www.youtube.com/watch?v=FM5dpxJMULY)\n- [Writing C# without allocating ANY memory](https://www.youtube.com/watch?v=B2yOjLyEZk0) - GuidTransformer sample taken from this video.\n- [Memory pools: github repo](https://github.com/sidristij/memory-pools) - Sidristij memory pools: including pools and traffic-free enumerable implementation.\n- [ValueStringBuilder: a stack-based string-builder](https://andrewlock.net/a-deep-dive-on-stringbuilder-part-6-vaulestringbuilder-a-stack-based-string-builder/)\n- [ValueStringBuilder: source code](https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/Text/ValueStringBuilder.cs)\n\n### In Russian\n- [Struct и readonly: как избежать падения производительности](https://habr.com/ru/company/microsoft/blog/423053/)\n- [RU - Станислав Сидристый — Делаем zero-allocation код на примере оптимизации крупной библиотеки](https://www.youtube.com/watch?v=-FDfnUyYSyc)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnazarovsa%2Fcsharp-zero-allocation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnazarovsa%2Fcsharp-zero-allocation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnazarovsa%2Fcsharp-zero-allocation/lists"}