ProgramingTip

씨 # /. NET에서 포인터를 사용하는 경우

bestdevel 2020. 11. 11. 20:29
반응형

씨 # /. NET에서 포인터를 사용하는 경우


저는 C #이 프로그래머에게 안전하지 않은 인터페이스에서 포인터를 액세스하고 사용할 수있는 기능을 제공한다는 것을 알고 있습니다. 그러나 이것이 언제 필요합니까?

어떤 상황에서 포인터 사용이 불가피한가요?

성능상의 이유 때문입니까?

또한 C #이 안전하지 않은 동적을 통해이 기능을 노출하고 여기에서 관리되는 모든 이점을 제거하는 이유는 무엇입니까? 이론적으로 관리 환경의 장점을 잃지 않고 사용하지 않고 있습니까?


이것이 언제 필요하면? 어떤 상황에서 포인터 사용이 불가 한 지나요?

관리되고 안전한 솔루션의 순 비용은 허용되지 않지만 안전하지 않습니다. 총 비용에서 총 이익을 빼서 순 비용 또는 순 이익을 얻을 수 있습니다. 안전하지 않은 솔루션의 이점은 "정확한 서비스를 보장하기 위해"와 같은 작동 검사에 시간을 사용할 수 없습니다. 비용은 (1) 관리되는 안전 시스템이 꺼진 상태 안전 코드를 작성해야하고, (2) 관리되지 않는 포인터 문제가있는 메모리를 사용하기 때문에 안전하지 않아서 가비지 수집기가 덜하게 만드는 것을 처리해야합니다. 그것.

또는 마샬링 레이어를 작성하는 사람이라면.

성능상의 이유 때문입니까?

성능 이외의 성능 관리 언어에서 포인터를 사용하는 것은 비뚤어진 것처럼 보입니다.

Marshal 클래스의 메서드를 사용하여 대부분의 경우 관리하지 않는 코드와의 상호 운용을 처리 할 수 ​​있습니다. (Interop 문제를 해결하기 위해 마샬링 장비를 사용하는 것이 어렵거나 불가능한 경우가 몇 가지있을 수 있습니다. 저는 전혀 전혀 없습니다.)

물론 내가 말했듯이 Marshal 클래스를 작성하는 사람이라면 문제를 해결하기 위해 마샬링 레이어를 사용할 수 없습니다 . 이 경우 포인터를 사용하여 구현해야합니다.

C #이 안전하지 않은 동적을 통해이 기능을 노출하고 관리되는 모든 이점을 제거하는 이유는 무엇입니까?

성능 관리 이점은 성능 비용이 많습니다. 예를 들어 배열에 열 번째 요소를 배치 할 때마다 가동은 열 번째 요소가 있는지 확인하고없는 경우 예외를 던져야합니다. 사용 비용이 제거됩니다.

이에 손상 처리하는 개발자 비용은 당신이 잘못하면, 당신은 당신의 하드 디스크를 포맷하고 오류 시점에서 깔끔한 예외를하기보다 한 시간 후에 프로세스를 충돌시키는 메모리 버그를 처리하게됩니다.

이론적으로 관리 환경의 장점을 잃지 않고 포인터를 사용할 수 있습니까?

"장점"이란 가비지 수집, 형식 및 참조 무결성과 같은 이점을 의미 가정합니다. 따라서 귀하의 질문은 어떤 것으로 "이론상 안전 시스템을 끌 수 있고 여전히 켜져있는 안전 시스템의 이점을 얻을 수 있습니까?"입니다. 아니, 분명합니다. 얼마나 비싼 지 마음에 들지 않아서 그 안전 시스템을 끄면 그 안전 시스템이 결과를 얻지 못합니다!


포인터는 관리되고 가비지 수집 된 환경에 대한 내부 인 모순입니다.
원시 포인터를 엉망으로 만들기 시작하면 GC는 무슨 일이 일어나고 있는지 전혀 알지 못합니다.

특히 포인터가 어디에 있는지 모르기 때문에 개체에 도달 할 수 있는지 여부를 알 수 없습니다.
또한 포인터가 깨질 수 있기 때문에 메모리에서 개체를 찾을 수 없습니다.

이 모든 것은 GC 추적 포인터로 해결됩니다. 그것이 참조가 무엇인지입니다.

복잡한 고급 interop 시나리오 또는 고도로 정교한 최적화를 위해서 많은 수가 있습니다.
당신이 원하는 경우라면, 아마하지 말아야 할 것입니다.


GC는 참조를 실행할 수 있습니다. 안전하지 않고 사용하면 개체가 GC의 제어 외부에 유지되고 방지 할 수 있습니다. "Fixed"는 개체를 고정하지만 GC가 메모리를 관리하도록합니다.

정의에 따라 주소에 대한 포인터가 있고 GC가 개체를 이동하면 포인터가 더 이상 유효하지 않습니다.

포인터가 필요한 이유 : 주된 이유는 관리되지 않는 DLL (예 : C ++로 DLL)을 사용하는 것입니다.

또한 변수를 고정하고 포인터를 사용할 때 힙 조각화에 더 취약합니다.


편집하다

관리 형 코드와 비 관리 형 코드의 핵심 문제를 다루었습니다. 메모리는 어떻게 해제 해제?

설명하는대로 성능을 위해 코드를 혼합 할 수 있습니다. 포인터로 관리 / 비 관리 경계를 넘을 수 없습니다 (즉, '안전하지 않은'컨텍스트 외부에서 포인터를 사용할 수 없습니다).

그들이 어떻게 청소 하느냐에 따라 ... 당신은 자신의 기억을 관리해야합니다. 포인터가 객체는 (대개 C ++ DLL 내에서) 생성 / 할당 (보통 C ++ DLL 내에서)를 사용 CoTaskMemAlloc()하여 호출하여 동일한 방식으로 해당 메모리를 해제해야합니다 CoTaskMemFree(). 개체 메모리 누수가 발생합니다. 로 할당 된 메모리 만 CoTaskMemAlloc()로 해제 할 수 있습니다 CoTaskMemFree().

다른 대안은 포인터를 가져 오는 방법을 사용할 방법 C ++ dll을 노출하는 것입니다. 이렇게하면 DLL이 메모리를 해제하는 방법을 사용할 수 있고 이는 메모리를 할당하기 위해 다른 방법을 사용하는 경우 가장 잘 작동합니다. 작업하는 대부분의 기본 dll은 일반적으로 호출 할 수있는 기본 dll은 일반적으로 호출 할 수있는 것입니다.

여기 에서 메모리 해제의 예 :

string[] array = new string[2];
array[0] = "hello";
array[1] = "world";
IntPtr ptr = test(array);
string result = Marshal.PtrToStringAuto(ptr);
Marshal.FreeCoTaskMem(ptr);
System.Console.WriteLine(result);


더 많은 읽기 자료 :

IntPtr참조하는 C # 메모리 할당 해제 두 번째 대답은 다른 할당 / 할당 해제 방법을 설명합니다.

C #에서 IntPtr을 해제하는 방법은 무엇입니까? 메모리가 할당 된 것과 동일한 방식으로 할당 해제 할 것을 강화합니다.

http://msdn.microsoft.com/en-us/library/aa366533%28VS.85%29.aspx 메모리를 할당하고 할당 해제하는 다양한 방법에 대한 공식 MSDN 문서.

간단히 말해서 ... 메모리를 해제하려면 메모리가 어떻게 할당되었는지 알아야합니다.


편집 질문을 올바르게 이해하면 짧은 대답은 '예'입니다. 관리되지 않는 포인터에 데이터를 전달하고, 안전하지 않은 컨텍스트에서 작업하고, 안전하지 않은 컨텍스트를 종료하면 데이터를 사용할 수 있습니다.

핵심은 참조하는 관리 객체를 fixed블록 으로 고정해야한다는 것 입니다. 이것은 참조하는 메모리가 unsafe블록 에있는 동안 GC에 의해 이동되는 것을 방지합니다 . 여기에는 여러 가지 미묘한 점이 포함되어 있습니다. 예를 들어 고정 블록에서 초기화 된 포인터를 재 할당 할 수 없습니다 ... 실제로 자신의 코드를 관리하도록 설정 한 경우 안전하지 않은 고정 문을 읽어야합니다.

즉, 자신의 개체를 관리하고 설명하는 방식으로 포인터를 사용하는 이점은 생각만큼 성능 향상을 얻지 못할 수 있습니다. 이유 :

  1. C #은 매우 최적화되고 매우 빠릅니다.
  2. 포인터 코드는 여전히 IL로 생성되므로 jitted해야합니다 (이 시점에서 추가 최적화가 작동합니다).
  3. 가비지 콜렉터를 끄는 것이 아닙니다. 작업중인 개체를 GC의 범위에서 벗어나게하는 것입니다. 따라서 100ms 정도마다 GC는 여전히 코드를 중단하고 관리 코드의 다른 모든 변수에 대해 해당 기능을 실행합니다.

HTH,
제임스


C #에서 명시 적으로 포인터를 사용하는 가장 일반적인 이유 :

  • 성능에 매우 민감한 저수준 작업 (예 : 문자열 조작)을 수행합니다.
  • 관리되지 않는 API와의 인터페이스.

포인터와 관련된 구문이 C #에서 제거 된 이유는 (내 지식과 관점에 따르면 Jon Skeet이 더 나은 B-라고 대답 할 것입니다) 대부분의 상황에서 불필요한 것으로 판명되었습니다.

언어 디자인 관점에서 가비지 수집기로 메모리를 관리하면 포인터로 수행 할 수있는 작업과 불가능한 작업에 대해 심각한 제약을 도입해야합니다. 예를 들어, 포인터를 사용하여 개체 중간을 가리키면 GC에 심각한 문제가 발생할 수 있습니다. 따라서 제한 사항이 적용되면 추가 구문을 생략하고 "자동"참조로 끝낼 수 있습니다.

또한 C / C ++에서 발견되는 매우 유익한 접근 방식은 일반적인 오류 원인입니다. 마이크로 성능이 전혀 중요하지 않은 대부분의 상황에서는 더 엄격한 규칙을 제공하고 발견하기 매우 어려운 버그를 줄 이도록 개발자를 제한하는 것이 좋습니다. 따라서 일반적인 비즈니스 응용 프로그램의 경우 .NET 및 Java와 같은 소위 "관리"환경이 베어 메탈 머신에 대해 작동하는 것으로 추정되는 언어보다 더 적합합니다.


IPC (공유 메모리)를 사용하여 두 응용 프로그램간에 통신하려는 경우 데이터를 메모리로 마샬링하고이 데이터 포인터를 Windows 메시징 등을 통해 다른 응용 프로그램에 전달할 수 있습니다. 응용 프로그램을받을 때 데이터를 다시 가져올 수 있습니다.

.NET에서 레거시 VB6 앱으로 데이터를 전송하는 경우에도 유용합니다. 여기서 데이터를 메모리로 마샬링하고, win msging을 사용하여 VB6 앱에 포인터를 전달하고, VB6 copymemory ()를 사용하여 관리되는 메모리 공간에서 VB6 앱 관리되지 않는 메모리로 데이터를 가져옵니다. 우주..

참고 URL : https://stackoverflow.com/questions/5171781/when-to-use-pointers-in-c-net

반응형