admin管理员组

文章数量:1122832

Consider a struct like this:

struct ExampleStruct
{
    public int ID;
    public List<ExampleStruct> children;
}

Would the following line of code create an object on the heap?

ExampleStruct exStrct = new Examplestruct() {ID = 5, children = null};

Consider a struct like this:

struct ExampleStruct
{
    public int ID;
    public List<ExampleStruct> children;
}

Would the following line of code create an object on the heap?

ExampleStruct exStrct = new Examplestruct() {ID = 5, children = null};
Share Improve this question edited Nov 21, 2024 at 15:29 trincot 349k35 gold badges270 silver badges320 bronze badges asked Nov 21, 2024 at 13:59 Amos EgelAmos Egel 1,18613 silver badges27 bronze badges 4
  • 7 No it won't. You can check the memory graph in SharpLab. – Good Night Nerd Pride Commented Nov 21, 2024 at 14:10
  • 1 One unrelated gotcha that you might not be aware of: in the above SharpLab example, the value v1 has no relation to v2.children[0], because v1 has been copied when it was inserted into v2.children. – Good Night Nerd Pride Commented Nov 21, 2024 at 14:15
  • @GoodNightNerdPride Thanks for the memory graph, that is a great feature. If you make your comment an answer, I'll accept it. – Amos Egel Commented Nov 22, 2024 at 7:39
  • 1 Of course, if exStrct can have it's lifetime extended (by being captured by a lambda, being in an async or iterator generated method, etc) then it will itself be placed in a heap object. Don't try to learn a billion separate rules for when/where memory allocations occur; if it's actually important for your specific situation, profile. – Damien_The_Unbeliever Commented Nov 27, 2024 at 12:04
Add a comment  | 

2 Answers 2

Reset to default 2

Would the following line of code create an object on the heap?

No. Since Examplestruct is a value type memory for it will be allocated on stack. Since you are not creating an instance of List<ExampleStruct> (which is a reference type) there is no need to allocate memory on the heap.

null denotes:

a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables

So there is nothing on the heap to point to, so no need to allocate anything there.

There are multiple ways to check this. For example by using GC.GetTotalAllocatedBytes(Boolean):

// "warm up"
Measure(() => new ExampleStruct() {ID = 5, children = null}, 10); 

Measure(() => new ExampleStruct() {ID = 5, children = null}, 10000);
Measure(() => new ExampleStruct() {ID = 5, children = new List<ExampleStruct>()}, 10000);

static void Measure(Action action, int iterations)
{
    var cur = GC.GetTotalAllocatedBytes(true);
    for (int i = 0; i < iterations; i++)
    {
        action();
    }

    Console.WriteLine($"Total Allocated Bytes: {GC.GetTotalAllocatedBytes(true) - cur:N0}");
}

Which prints "on my machine":

Total Allocated Bytes: 2,008
Total Allocated Bytes: 0
Total Allocated Bytes: 320,288

If you put this code inside a test class... and set two breakpoints at the arrange and assert calls, you will be able to use the diagnotics window in VS2022 to inspect the details

Microsoft documentation for VS2022

struct ExampleStruct
{
    public int ID;
    public List<ExampleStruct> children;
}

public class StackOverflowStructQ
{
    [Fact]
    public void Method_Condition_Expectation()
    {
        // Arrange
        ExampleStruct es = new() { ID = 1, children = [] };

        // Act

        // Assert
        Assert.NotNull(es.children);
    }
}

The when the first breakpoint is hit - "take a snapshot" from the Diagnostics window.

You should be able to drill down and see "Referenced Objects". This means the reference is stored in the struct, but the object it references is stored on the heap.

So try and keep your structs lightweight. If you need to reference objects which will ultimately reside on the heap, probably best to use a class?

本文标签: cStruct with fields of List typebut set to null Heap allocationStack Overflow