문제
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에서 물건을 움직일 수 있다는 위험을 지적합니다.