.net 관리 메모리는 객체 내부의 값 유형을 어떻게 처리합니까?

StackOverflow https://stackoverflow.com/questions/24829

  •  09-06-2019
  •  | 
  •  

문제

public class MyClass
{
    public int Age;
    public int ID;
}

public void MyMethod() 
{
    MyClass m = new MyClass();
    int newID;
}

내가 이해한 바에 따르면 다음은 사실입니다.

  1. 참조 m은 스택에 있으며 MyMethod()가 종료되면 범위를 벗어납니다.
  2. newID 값 유형은 스택에 존재하며 MyMethod()가 종료되면 범위를 벗어납니다.
  3. new 연산자에 의해 생성된 객체는 힙에 존재하며 객체에 대한 다른 참조가 존재하지 않는다는 가정 하에 MyMethod()가 종료될 때 GC에 의해 회수 가능해집니다.

내 질문은 다음과 같습니다.

  1. 객체 내의 값 유형이 스택이나 힙에 있습니까?
  2. 개체의 boxing/unboxing 값 유형이 문제가 됩니까?
  3. 이 주제에 대해 상세하면서도 이해하기 쉬운 리소스가 있습니까?

논리적으로 클래스 내부의 값 유형이 힙에 있을 것이라고 생각하지만, 거기에 도달하기 위해 박스로 묶어야 하는지는 잘 모르겠습니다.

편집하다:

이 주제에 대한 권장 읽기 자료:

  1. Jeffrey Richter의 CLR Via C#
  2. Don Box의 필수 .NET
도움이 되었습니까?

해결책

클래스의 값 유형 값 가지다 관리되는 힙의 개체 인스턴스와 함께 작동합니다.메서드에 대한 스레드 스택은 메서드가 지속되는 동안에만 유지됩니다.해당 스택 내에만 존재하는 경우 값이 어떻게 지속될 수 있습니까?

관리되는 힙에 있는 클래스의 개체 크기는 해당 값 형식 필드, 참조 형식 포인터 및 동기화 블록 인덱스와 같은 추가 CLR 오버헤드 변수의 합계입니다.개체의 값 유형 필드에 값을 할당하면 CLR은 해당 특정 필드에 대해 개체 내에 할당된 공간에 값을 복사합니다.

단일 필드가 있는 간단한 클래스를 예로 들어 보겠습니다.

public class EmbeddedValues
{
  public int NumberField;
}

그리고 간단한 테스트 수업도 있습니다.

public class EmbeddedTest
{
  public void TestEmbeddedValues()
  {
    EmbeddedValues valueContainer = new EmbeddedValues();

    valueContainer.NumberField = 20;
    int publicField = valueContainer.NumberField;
  }
}

.NET Framework SDK에서 제공하는 MSIL 디스어셈블러를 사용하여 EmbeddedTest.TestEmbeddedValues()에 대한 IL 코드를 엿보는 경우

.method public hidebysig instance void  TestEmbeddedValues() cil managed
{
  // Code size       23 (0x17)
  .maxstack  2
  .locals init ([0] class soapextensions.EmbeddedValues valueContainer,
           [1] int32 publicField)
  IL_0000:  nop
  IL_0001:  newobj     instance void soapextensions.EmbeddedValues::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.s   20
  IL_000a:  stfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_000f:  ldloc.0
  IL_0010:  ldfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_0015:  stloc.1
  IL_0016:  ret
} // end of method EmbeddedTest::TestEmbeddedValues

CLR이 다음과 같은 지시를 받고 있음을 주목하세요. stfld 스택에 로드된 값 "20"을 로드된 EmbeddValues의 NumberField 필드 위치로, 관리되는 힙으로 직접 가져옵니다.마찬가지로 값을 검색할 때 다음을 사용합니다. ldfld 관리되는 힙 위치의 값을 스레드 스택에 직접 복사하는 명령입니다.이러한 유형의 작업에서는 상자/개봉이 발생하지 않습니다.

다른 팁

  1. 객체가 소유하는 모든 참조 또는 값 유형은 힙에 있습니다.
  2. 인트를 개체로 캐스팅하는 경우에만

The best resource I've seen for this is the book CLR via C# by Jeffrey Richter. It's well worth reading if you do any .NET development. Based on that text, my understanding is that the value types within a reference type do live in the heap embedded in the parent object. Reference types are always on the heap. Boxing and unboxing are not symmetric. Boxing can be a bigger concern than unboxing. Boxing will require copying the contents of the value type from the stack to the heap. Depending on how frequently this happens to you there may be no point in having a struct instead of a class. If you have some performance critical code and you're not sure if boxing and unboxing is happening use a tool to examine the IL code of your method. You'll see the words box and unbox in the IL. Personally, I would measure the performance of my code and only then see if this is a candidate for worry. In your case I don't think this will be such a critical issue. You are not going to have to copy from the stack to the heap (box) every time you access this value type inside the reference type. That scenario is where boxing becomes a more meaningful problem.

  • Ans#1: Heap. Paraphrasing Don Box from his excellent 'Essential .Net Vol 1'

Reference Types(RT) always yield instances that are allocated on the heap. In contrast, value types(VT) are dependent on the context - If a local var is a VT, the CLR allocates memory on the stack. If a field in a class is a member of a VT, then the CLR allocates memory for the instance as part of the layout of the object/Type in which field is declared.

  • Ans#2: No. Boxing would occur only when you access a struct via a Object Reference / Interface Pointer. obInstance.VT_typedfield will not box.

    RT variables contains the address of the object it refers to. 2 RT var can point to the same object. In contrast, VT variables are the instances themselves. 2 VT var cannot point to same object(struct)

  • Ans#3: Don Box's Essential .net / Jeffrey Richter's CLR via C#. I have a copy of the former... though the later may be more updated for .Net revisions

Do value types within objects live on the stack or the heap?

On the heap. They are part of the allocation of the footprint of the object, just like the pointers to hold references would be.

Is boxing/unboxing value types in an object a concern?

There's no boxing here.

Are there any detailed, yet understandable, resources on this topic?

+1 vote for Richter's book.

A variable or other storage location of a structure type is an aggregation of that type's public and private instance fields. Given

struct Foo {public int x,y; int z;}

a declaration Foo bar; will cause bar.x, bar.y, and bar.z to be stored wherever bar is going to be stored. Adding such a declaration of bar to a class will, from a storage-layout perspective, be equivalent to adding three int fields. Indeed, if one never did anything with bar except access its fields, the fields of bar would behave the same as would three fields bar_x, bar_y, and bar_cantaccessthis_z [accessing the last one would require doing things with bar other than accessing its fields, but it would take up space whether or not it's ever actually used for anything].

Recognizing structure-type storage locations as being aggregations of fields is the first step to understanding structures. Trying to view them as holding some kind of object might seem "simpler", but doesn't match how they actually work.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top