2011-08-01 2 views
2

.Net 프로그램에서 GC가 너무 빠름을 처리하고 있습니다. 네이티브 리소스가있는 클래스를 사용하고 GC.KeepAlive()를 호출하지 않기 때문에 GC는 네이티브 액세스가 끝나기 전에 개체를 수집합니다. 결과적으로 프로그램이 충돌합니다. 그래서 같이JIT가 범위 끝까지 스택 변수를 확장하는 방법 (GC가 너무 빠름)

Does the .NET garbage collector perform predictive analysis of code?

: 여기에 설명 된대로 우리는 정확히 문제가

{ var img = new ImageWithNativePtr(); 
    IntPtr p = img.GetData(); 
    // DANGER! 
    ProcessData(p); 
} 

점은 : JIT는 IMG가 점하는 경우에 사용하지 않는 GC를 보여줍니다 정보를 생성 GetData()가 실행됩니다. GC- 쓰레드가 적시에 올 경우, img를 수집하고 프로그램이 충돌합니다. GC.KeepAlive (img)를 추가하여이 문제를 해결할 수 있습니다. 불행히도 이미 너무 많은 코드가 작성되어 (너무 많은 곳에서) 문제를 쉽게 해결할 수 있습니다.

따라서 : 예를 들어 JIT가 디버그 빌드에서와 같이 작동하도록하는 속성 (예 : ImageWithNativePtr)이 있습니까? 디버그 빌드에서 변수 img는 범위 (}) 끝까지 유효하게 유지되지만 릴리스에서는 댓글 DANGER에서 유효성이 느슨합니다.

+0

'GC.KeepAlive'가 유일한 옵션입니다. –

+0

관리되지 않는 리소스가 일종의 처분을 필요로하지 않습니까? –

+1

어리석은 구현에 의존하는 코드가 깨졌습니다. – delnan

답변

2

내가 알고있는 한, 메소드가 참조하는 유형에 따라 지터의 동작을 제어 할 수있는 방법이 없습니다. 메소드 자체를 특성화 할 수는 있지만 주문을 채울 수는 없습니다. 그렇기 때문에 글 머리 기호를 물고 코드를 다시 작성해야합니다. GC.KeepAlive이 하나의 옵션입니다. 다른 하나는 GetData이 객체에 대한 참조를 포함하는 안전한 핸들을 반환하도록하고 IntPtr 대신에 ProcessData이 핸들을 허용하도록하는 것입니다. 어쨌든 좋은 방법입니다. GC는 메서드가 반환 될 때까지 안전한 핸들을 유지합니다. 코드 조각에 IntPtr 대신 코드 대부분이 var 인 경우 각 방법을 수정하지 않고도 빠져 나갈 수 있습니다.

+0

안전한 핸들/전용 객체가 가능하지 않은 경우 가장 표현적인 구문 (KeepAlive 대신)은'ImageWithNativePtr'을'IDisposable'로 구현하고'using (var img = new ImageWithNativePtr()) {...}' –

+0

사실,하지만 더 많은 코드 변경이 필요합니다. 전체'ImageWithNativePtr'는'SafeHandle'에서 파생 될 수 있습니다. –

+0

IDisposable 전략은 물론 생각했습니다 - 그러나 코드 변경이 필요합니다. 아직 붙잡을 수있는 유일한 방법은 여전히 ​​지침의 범위 지정입니다. 그러나 우리가 알고 있듯이 GC는 더 빠른 작업을 수행합니다. – Hui

1

몇 가지 옵션이 있습니다.

  1. 이 (더 정확한 작업이 필요합니다) - 그것은 살아 당신이 using들과 코드를 업데이트에서 제공하는 개체를 유지합니다 try { ... } finally { object.Dispose() }, 아래로 컴파일로 ImageWithNativePtr 클래스 IDisposable를 구현합니다. CodeRush와 같은 것을 설치하면 (이 경우에도 무료 Xpress이 지원됩니다) - using 블록 생성을 지원하므로이 작업을 쉽게 할 수 있습니다.
  2. (더 쉽고 정확하지 않으며 더 복잡한 빌드) - Post Sharp 또는 Mono.Cecil을 사용하고 고유 한 특성을 만드십시오. 일반적으로이 특성을 사용하면 GC.KeepAlive()가 이러한 메서드에 삽입됩니다.

CLR에는이 기능이 내장되어 있지 않습니다.

0

IDispose 및 using 문을 구현하는 컨테이너로 원하는 것을 에뮬레이트 할 수 있다고 생각합니다. using 문을 사용하면 범위를 정의 할 수 있으며 해당 범위에서 살아 있어야 할 필요가있는 내용을 원하는 위치에 배치 할 수 있습니다. ImageWithNativePtr의 구현을 제어 할 수없는 경우, 이것은 도움이되는기구가 될 수 있습니다.

처리 할 물건의 컨테이너는 유용한 관용구입니다. 특히 당신이 정말로 뭔가를 버려야 할 때 ... 아마 이미지가있는 경우 일 것입니다.

using(var keepAliveContainer = new KeepAliveContainer()) 
{ 
    var img = new ImageWithNativePtr(); 
    keepAliveContainer.Add(img); 
    IntPtr p = img.GetData(); 
    ProcessData(p); 
    // anything added to the container is still referenced here. 
} 
+0

좋은 아이디어 - 이미지를 생성자 매개 변수로 넣을 수도 있지만. – Hui

관련 문제