문제

C#에서는 다음과 같은 포인터 유형 멤버가있는 구조물 (또는 클래스)을 선언 할 수 있습니다.

unsafe struct Node
{
  public Node* NextNode;
}

안전한가? unsafe 깃발 ..)이 구성을 사용하려면? 힙에 장기 보관을 의미합니다. 내가 이해 한 바에 따르면, GC는 자유롭게 물건을 움직일 수 있으며, 움직인 것에 대한 참조를 업데이트하는 동안 포인터도 업데이트됩니까? 나는이 건축이 매우 안전하지 않게 만드는 것이 아니라고 생각합니다.

나는 이것을하는 데 대한 우수한 대안이 있다고 확신하지만, 그것을 병적 호기심이라고 부릅니다.

편집 : 혼란이있는 것 같습니다. 나는 이것이 큰 건축이 아니라는 것을 알고 있습니다. 전혀 이것이 안전한 구조인지를 알고 싶습니다. 즉, 포인터는 원래 지적한 것을 계속 지적 할 수 있습니까?

원래 C 코드는 재귀없이 트리 (깊이 우선)를 가로 지르는 데 사용되었으며, 여기서 트리는 어레이에 저장됩니다. 그런 다음 특정 조건이 충족되지 않는 한, 배열은 포인터를 증가시킴으로써 트래버스를 횡단하고, 포인터는 다음 노드로 설정되어 트래버스가 계속됩니다. 물론 C#의 동일한 캔은 다음과 같이 수행 할 수 있습니다.

struct Node
{
  public int NextNode;
  ... // other fields
}

어디에 int 다음 노드 배열의 인덱스입니다. 그러나 공연의 이유로, 나는 포인터와 함께 가고 fixed 어쨌든 바운드 점검을 피하기위한 배열과 원래 C 코드가 더 자연스럽게 보였습니다.

도움이 되었습니까?

해결책

이 건축을 사용하는 것이 안전합니까? 힙에 장기 보관을 의미합니다.

예. 그렇게하는 것은 보통 어리 석고 고통스럽고 불필요하지만 가능합니다.

내가 이해 한 바에 따르면, GC는 자유롭게 물건을 움직일 수 있으며, 움직인 것에 대한 참조를 업데이트하는 동안 포인터도 업데이트됩니까?

아니. 그렇기 때문에 우리는 당신이 그것을 안전하지 않은 것으로 표시하게합니다.

나는이 건축이 매우 안전하지 않게 만드는 것이 아니라고 생각합니다.

옳은.

나는 이것을하는 데 대한 우수한 대안이 있다고 확신하지만, 그것을 병적 호기심이라고 부릅니다.

확실히 있습니다.

포인터는 원래 지적한 것을 계속 지적 할 수 있습니까?

그런 일이 발생하지 않는 한 아닙니다. 그렇게하는 두 가지 방법이 있습니다.

방법 1 : 쓰레기 수집가에게 메모리를 움직이지 말라고 지시하십시오. 그렇게하는 두 가지 방법이 있습니다.

  • "고정 된"명령문으로 변수를 고정하십시오.

  • Interop 서비스를 사용하여 살아 있고 한 곳에 유지하려는 구조물에 GC 핸들을 만듭니다.

이러한 일 중 하나를 수행하면 가비지 수집가의 성능이 높은 가능성이 높아집니다.

웨이 2 : 쓰레기 수집가가 움직일 수있는 메모리에 대한 언급을받지 마십시오. 그렇게하는 두 가지 방법이 있습니다.

  • 로컬 변수, 값 매개 변수 또는 스택 할당 블록의 주소 만 가져옵니다. 물론 그렇게하면 포인터가 관련 스택 프레임보다 오래 살아남지 않도록해야합니다. 그렇지 않으면 쓰레기를 참조하고 있습니다.

  • 관리되지 않은 힙에서 블록을 할당 한 다음 해당 블록 내부에 포인터를 사용하십시오. Essense에서는 자신의 메모리 관리자를 구현하십시오. 새로운 사용자 정의 메모리 관리자를 올바르게 구현해야합니다. 조심하세요.

다른 팁

왜 안 돼:

struct Node
{
    public Node NextNode;
}

아니면 적어도:

struct Node
{
    public IntPtr NextNode;
}

당신은 사용할 수 있습니다 결정된 GC가 포인터를 움직이지 못하게하는 진술.

예, 쓰레기 수집기는 물체를 움직일 수 있으며 포인터를 업데이트하지 않습니다. 당신은 당신이 가리키는 객체를 수정해야합니다. 자세한 내용은 이것에 대해 확인할 수 있습니다 메모리 관리 설명.

다음과 같은 개체를 수정할 수 있습니다.

  unsafe {
     fixed (byte* pPtr = object) {
         // This will fix object in the memory
        }
     }
  }

포인터의 장점은 일반적으로 다른 안전하지 않은 코드와의 성능과 상호 작용입니다. 코드를 속도를 높이기 위해 바운드 외 점검 등이 없을 것입니다. 그러나 당신이 예를 들어, 예를 들어 프로그래밍하는 것처럼 당신은 당신이하고있는 일에 매우주의해야합니다.

명백한 무결성 점검은 제외되었습니다. 이것의 명백한 문제는 키워드로 버퍼를 재 할당 할 수 없기 때문에 필요한 것보다 더 많은 것을 할당해야한다는 것입니다. 결정된 암시합니다.

public unsafe class NodeList
{
    fixed Node _Nodes[1024];
    Node* _Current;

    public NodeList(params String[] data)
    {
        for (int i = 0; i < data.Length; i++)
        {
            _Nodes[i].Data = data[i];
            _Nodes[i].Next = (i < data.Length ? &_Nodes[i + 1] : null);     
        }

        _Current = &_Nodes[0];
    }

    public Node* Current()
    {
        return _Current++;  
    }
}

public unsafe struct Node
{
    public String Data;
    public Node* Next;
}

위험한 아이디어이지만 효과가있을 수 있습니다.

구조 배열이 특정 크기 (85000 바이트)를 초과하면 큰 물체 힙 블록을 스캔하고 수집하지만 이동하지 않은 곳 ...

링크 된 기사는 새로운 CLR 버전이 LOH에서 물건을 움직일 수 있다는 위험을 지적합니다.

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