문제

나는 이 기능을 사용하는 것의 심각한 의미를 이해하지만(또는 적어도 내 생각에는 그렇게 생각합니다), 왜 이 기능이 존경받는 프로그래머, 심지어 알지도 못하는 프로그래머가 사용하지 않는 기능 중 하나가 되었는지 이해하지 못합니다. 그것이 무엇을 위한 것인지.

사용자가 수행하는 작업에 따라 메모리 사용량이 크게 달라지는 애플리케이션을 개발 중이라고 가정해 보겠습니다.애플리케이션 수명주기는 두 가지 주요 단계로 나눌 수 있습니다.편집 및 실시간 처리.편집 단계에서 수십억, 심지어는 수조 개의 개체가 생성된다고 가정해 보겠습니다.그 중 일부는 작고 일부는 그렇지 않습니다. 일부는 종료자가 있을 수 있고 일부는 그렇지 않을 수 있으며 수명은 몇 밀리초에서 긴 시간까지 다양하다고 가정합니다.다음으로 사용자는 실시간 단계로 전환하기로 결정합니다.이 시점에서 성능이 근본적인 역할을 하고 프로그램 흐름이 조금만 변경되면 치명적인 결과를 초래할 수 있다고 가정해 보겠습니다.그런 다음 개체 풀 등을 사용하여 개체 생성을 가능한 한 최소화하지만 GC가 예기치 않게 차임되어 모든 것을 버리고 누군가가 죽습니다.

질문:이런 경우에는 두 번째 단계로 들어가기 전에 GC.Collect()를 호출하는 것이 현명하지 않을까요?

결국, 이 두 단계는 서로 시간적으로 겹치지 않으며 GC가 수집할 수 있는 모든 최적화 및 통계는 여기서 거의 쓸모가 없습니다...

메모:여러분 중 일부가 지적했듯이 .NET은 이와 같은 응용 프로그램에 가장 적합한 플랫폼이 아닐 수도 있지만 이는 이 질문의 범위를 벗어납니다.GC.Collect() 호출이 애플리케이션의 전반적인 동작/성능을 향상시킬 수 있는지 여부를 명확히 하는 것이 목적입니다.우리 모두는 그런 일을 하는 상황이 극히 드물다는 데 동의합니다. 하지만 GC는 추측을 시도하고 대부분의 경우 완벽하게 수행하지만 여전히 추측에 관한 것입니다.

감사해요.

도움이 되었습니까?

해결책

Rico의 블로그에서...

규칙 #1

하지 않다.

이것은 실제로 가장 중요한 규칙입니다.GC.Collect ()의 대부분의 사용법은 나쁜 생각이며 Orginal 게시물에서 자세히 설명 했으므로 여기에서 모든 것을 반복하지는 않습니다.그럼 다음으로 넘어가겠습니다...

규칙 #2

일부 재생이없는 이벤트가 방금 발생 했고이 ​​이벤트로 인해 많은 오래된 물건이 죽을 가능성이 높으면 GC.collect ()에게 전화하십시오.

이에 대한 전형적인 예는 클라이언트 애플리케이션을 작성하고 그와 관련된 많은 데이터가있는 매우 크고 복잡한 형태를 표시하는 것입니다.사용자는이 양식과 상호 작용하여 잠재적으로 큰 객체를 생성했습니다 ...XML 문서 또는 큰 데이터 세트 또는 2와 같은 것들.양식이 닫히면이 객체가 죽었고 gc.collect ()는 그들과 관련된 메모리를 되 찾을 것입니다 ...

따라서 이 상황은 규칙 #2에 해당할 수 있는 것처럼 들립니다. 많은 오래된 개체가 죽는 순간이 있고 이는 반복되지 않는다는 것을 알고 있습니다.그러나 리코의 이별의 말을 잊지 마십시오.

규칙 #1은 강력한 증거없이 규칙 #2를 능가해야합니다.

측정, 측정, 측정.

다른 팁

프로덕션 코드에서 GC.Collect()를 호출하면 본질적으로 GC 작성자보다 더 많은 것을 알고 있다고 선언하는 것입니다.그럴 수도 있습니다.그러나 일반적으로 그렇지 않으므로 강력히 권장하지 않습니다.

그렇다면 .NET에서 MS Word 또는 MS Excel과 같은 COM 개체를 사용하는 경우는 어떻습니까?전화도 없이 GC.Collect COM 개체를 해제한 후에도 Word 또는 Excel 응용 프로그램 인스턴스가 여전히 존재한다는 것을 발견했습니다.

실제로 우리가 사용하는 코드는 다음과 같습니다.

Utils.ReleaseCOMObject(objExcel)

' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its 
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process, 
' but one that may be necessary when automating Excel because it is the only way to 
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

그렇다면 가비지 수집기를 잘못 사용하는 것입니까?그렇다면 Interop 개체가 죽도록 하려면 어떻게 해야 합니까?또한 이렇게 사용하도록 의도된 것이 아니라면 왜 GC'에스 Collect 방법조차도 Public?

글쎄요, GC는 제가 애증/애증 관계를 맺고 있는 것 중 하나입니다.우리는 예전에 깨뜨렸어 VistaDB를 통해 이에 대해 블로그에 올렸습니다.그들은 그것을 고쳤지만 이와 같은 문제를 고치는 데 오랜 시간이 걸립니다.

GC는 복잡하며 모든 접근 방식에 맞는 단일 크기는 이렇게 큰 작업을 수행하기가 매우 어렵습니다.MS는 꽤 좋은 일을 해냈지만 때때로 GC를 속이는 것이 가능합니다.

일반적으로 Collect 당신이 사실을 알지 않는 한, 당신은 엄청난 양의 메모리를 버렸고 그것은 중년의 위기 GC가 지금 정리되지 않으면 지금 정리됩니다.

일련의 불량으로 전체 기계를 망칠 수 있습니다. GC.Collect 진술.Collect 문의 필요성은 거의 항상 더 큰 기본 오류를 가리킵니다.메모리 누수는 일반적으로 참조 및 작동 방식에 대한 이해 부족과 관련이 있습니다.또는 IDisposable 필요하지 않은 개체에 대해 GC에 훨씬 더 높은 부하를 가하는 것입니다.

시스템 성능 카운터를 통해 GC에 소요된 시간(%)을 면밀히 관찰하세요.앱이 GC에서 시간의 20% 이상을 사용하는 경우 심각한 개체 관리 문제(또는 비정상적인 사용 패턴)가 있는 것입니다.전체 앱 속도가 빨라지므로 GC에 소요되는 시간을 항상 최소화하려고 합니다.

GC는 워크스테이션과 서버에서 다르다는 점을 기억하는 것도 중요합니다.나는 사람들이 두 가지를 모두 테스트하지 않는(또는 두 가지가 있다는 사실조차 인식하지 못하는) 문제를 추적하기 어려운 여러 가지 작은 문제를 보았습니다.

그리고 가능한 한 내 답변을 최대한 자세히 설명하려면 해당 플랫폼을 대상으로 하는 경우 Mono에서도 테스트해야 합니다.완전히 다른 구현이므로 MS 구현과 완전히 다른 문제가 발생할 수 있습니다.

유용한 상황이 있지만 일반적으로 피해야 합니다.GOTO 또는 오토바이 타기와 비교할 수 있습니다.필요할 때 그렇게 하지만 친구들에게는 말하지 않습니다.

내 경험에 따르면 프로덕션 코드에서 GC.Collect()를 호출하는 것은 결코 권장되지 않습니다.디버깅에서는 그렇습니다. 잠재적인 메모리 누수를 명확히 하는 데 도움이 되는 이점이 있습니다.내 근본적인 이유는 GC가 나보다 훨씬 더 똑똑한 프로그래머에 의해 작성되고 최적화되었기 때문이라고 생각합니다. 그리고 GC.Collect()를 호출해야 한다고 느끼는 지점에 도달하면 이는 내가 길을 벗어났다는 단서입니다. 어딘가에.귀하의 상황에서는 실제로 메모리 문제가 있는 것 같지 않고 단지 컬렉션이 프로세스에 어떤 불안정성을 가져올지 걱정하고 있는 것 같습니다.아직 사용 중인 물건을 치워주지도 않고 수요의 증가와 감소에 매우 빠르게 적응한다는 점을 고려하면 걱정하지 않으셔도 될 것 같습니다.

GC.Collect()를 호출하는 가장 큰 이유 중 하나는 설명하는 것과 같이 많은 쓰레기를 생성하는 중요한 이벤트를 방금 수행했을 때입니다.여기서는 GC.Collect()를 호출하는 것이 좋습니다.그렇지 않으면 GC가 '일회성' 이벤트라는 것을 이해하지 못할 수도 있습니다.

물론 프로필을 작성하고 직접 확인해야 합니다.

물론 실시간이 아닌 가비지 수집 기능이 있는 언어로 실시간 요구 사항이 포함된 코드를 작성해서는 안 됩니다.

단계가 잘 정의된 경우 가비지 수집기를 트리거하는 데 문제가 없습니다.하지만 이런 경우는 극히 드뭅니다.문제는 많은 개발자들이 이를 카고컬트 스타일의 문제를 페이퍼 오버해서 사용하려고 하는데, 무분별하게 추가하면 성능 문제가 발생한다는 점이다.

GC.Collect()를 호출하면 CLR이 스택 워크를 수행하여 참조를 확인하여 각 객체가 실제로 해제될 수 있는지 확인합니다.이는 개체 수가 많은 경우 확장성에 영향을 미치며 가비지 수집을 너무 자주 트리거하는 것으로 알려져 있습니다.CLR을 신뢰하고 적절한 경우 가비지 수집기가 자체적으로 실행되도록 하십시오.

루프에서 이미지 생성 - dispose를 호출하더라도 메모리가 복구되지 않습니다.쓰레기는 매번 수집됩니다.사진 처리 앱의 메모리가 1.7GB에서 24MB로 늘어났는데 성능이 뛰어납니다.

GC.Collect를 호출해야 할 때가 분명히 있습니다.

사실, 저는 GC.Collect를 호출하는 것이 아주 나쁜 습관이라고 생각하지 않습니다.
그럴 필요가 있는 경우가 있을 수 있습니다.예를 들어, 스레드를 실행하여 데이터베이스에서 다른 테이블을 열고, BLOB 필드의 내용을 임시 파일로 추출하고, 파일을 암호화한 다음, 파일을 바이너리 스트림으로 읽고 다시 BLOB로 읽는 양식이 있습니다. 다른 테이블의 필드입니다.

전체 작업에는 꽤 많은 메모리가 필요하며 테이블의 행 수와 파일 내용의 크기가 확실하지 않습니다.

OutofMemory Exception이 자주 발생했는데 카운터 변수를 기반으로 GC.Collect를 주기적으로 실행하는 것이 현명할 것이라고 생각했습니다.카운터를 증가시키고 지정된 수준에 도달하면 형성되었을 수 있는 모든 쓰레기를 수집하고 예상치 못한 메모리 누수로 인해 손실된 메모리를 회수하기 위해 GC가 호출됩니다.

그 후에는 적어도 예외 없이 잘 작동하는 것 같아요!!!
나는 다음과 같은 방법으로 전화합니다.

var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).

.net에서 가비지 수집을 수행하는 데 필요한 시간은 쓰레기의 양보다 쓰레기가 아닌 항목의 양과 훨씬 더 밀접한 관련이 있습니다.실제로 객체가 재정의되지 않는 한 Finalize (명시적으로 또는 C# 소멸자를 통해) WeakReference, 대형 개체 힙에 위치하거나 다른 gc 관련 방식에서 특수한 경우 개체로 존재하는 메모리를 식별하는 유일한 방법은 해당 개체에 대한 루트 참조가 존재한다는 것입니다.그렇지 않으면 GC의 운영은 건물에서 가치 있는 모든 것을 가져와 건물을 역동적으로 만들고 이전 건물 자리에 새 건물을 짓고 모든 귀중한 항목을 그 안에 넣는 것과 유사합니다.건물을 다이너마이트하는 데 필요한 노력은 건물 안에 있는 쓰레기의 양과 완전히 별개입니다.

결과적으로 전화 GC.Collect 시스템이 수행해야 하는 전체 작업량이 증가하는 경향이 있습니다.이는 다음 수집의 발생을 지연시키지만 아마도 다음 수집이 발생했을 때 필요한 만큼의 작업을 즉시 수행할 것입니다.다음 수집이 발생했을 시점에서 수집에 소요된 총 시간은 이전 수집과 거의 같았을 것입니다. GC.Collect 호출되지 않았지만 시스템에 일부 가비지가 축적되어 이전보다 더 빨리 후속 수집이 필요하게 됩니다. GC.Collect 호출되지 않았습니다.

내가 볼 수 있는 시간들 GC.Collect 실제로 유용한 것은 일부 코드의 메모리 사용량을 측정해야 하거나(메모리 사용량 수치는 컬렉션 이후에만 의미가 있으므로) 여러 알고리즘 중 어느 것이 더 나은지 프로파일링해야 하는 경우(여러 알고리즘을 각각 실행하기 전에 GC.Collect() 호출)입니다. 코드 조각은 일관된 기준 상태를 보장하는 데 도움이 될 수 있습니다.GC가 모르는 것을 알 수 있는 몇 가지 다른 경우가 있지만 단일 스레드 프로그램을 작성하지 않는 한 GC가 무엇인지 알 수 있는 방법은 없습니다. GC.Collect 한 스레드의 데이터 구조가 "중년 위기"를 피하는 데 도움이 되는 호출은 다른 스레드의 데이터에 그렇지 않으면 피할 수 있는 "중년 위기"를 발생시키지 않습니다.

가비지 수집기가 가비지를 수집하지 않고 메모리를 확보하지 못하는 것과 비슷한 문제가 있었습니다.

우리 프로그램에서는 OpenXML을 사용하여 적당한 크기의 Excel 스프레드시트를 처리하고 있었습니다.스프레드시트에는 14개의 열로 구성된 약 1000개의 행이 있는 5~10개의 "시트"가 포함되어 있습니다.

32비트 환경(x86)의 프로그램은 "메모리 부족" 오류로 인해 충돌이 발생했습니다.우리는 x64 환경에서 실행되도록 했지만 더 나은 솔루션을 원했습니다.

우리는 하나를 찾았습니다.

다음은 삭제된 개체에서 메모리를 확보하기 위해 가비지 수집기를 명시적으로 호출할 때 작동하지 않은 부분과 작동했던 부분에 대한 몇 가지 단순화된 코드 조각입니다.

서브루틴 내부에서 GC 호출이 작동하지 않았습니다.메모리는 회수되지 않았습니다 ...

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
End Sub

GC 호출을 서브루틴 범위 외부로 이동하면 가비지가 수집되고 메모리가 해제됩니다.

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
End Sub

.NET 가비지 수집이 호출을 무시하는 것처럼 보일 때 좌절감을 느끼는 다른 사람들에게 이것이 도움이 되기를 바랍니다. GC.Collect().

폴 스미스

컬렉션을 명시적으로 호출하는 데에는 아무런 문제가 없습니다.어떤 사람들은 그것이 벤더가 제공하는 서비스라면 의심하지 말라고 정말로 믿고 싶어합니다.아, 그리고 대화형 애플리케이션이 잘못된 순간에 무작위로 멈추는 경우가 있나요?다음 버전에서는 더 나아질 것입니다!

백그라운드 프로세스가 메모리 조작을 처리하도록 한다는 것은 실제로 이를 직접 처리할 필요가 없다는 것을 의미합니다.그러나 이것은 논리적으로 모든 상황에서 우리가 스스로 문제를 처리하지 않는 것이 최선이라는 것을 의미하지는 않습니다.GC는 대부분의 경우에 최적화되어 있습니다.하지만 이것이 논리적으로 모든 경우에 최적화되어 있다는 의미는 아닙니다.

'가장 좋은 정렬 알고리즘은 무엇인가'와 같은 개방형 질문에 확실한 답으로 답한 적이 있나요?그렇다면 GC를 건드리지 마세요.조건을 물어보시거나, '이 경우'라고 답변해주신 분들을 위해 GC에 대한 내용과 활성화 시기를 알아보실 수 있습니다.

Chrome과 Firefox에서 애플리케이션이 정지되어 정말 짜증나는 일이 있었고 심지어 어떤 경우에는 메모리가 방해 없이 늘어나기도 했습니다. 만약 그들이 가비지 컬렉터를 호출하는 방법을 배우거나 나에게 페이지의 텍스트를 읽기 시작할 때 버튼을 누르면 다음 20분 동안 정지 현상이 발생하지 않습니다.

시나리오에 대해서는 귀하가 옳다고 생각하지만 API에 대해서는 잘 모르겠습니다.

Microsoft에서는 이러한 경우 다음과 같이 해야 한다고 말합니다. 메모리 압박 추가 곧 수집을 수행해야 한다는 GC에 대한 힌트로 사용됩니다.

무슨 문제가 있나요?가비지 수집기와 메모리 할당자에 대해 다시 추측하고 있다는 사실은 이들 사이에서 런타임 시 애플리케이션의 실제 메모리 사용량에 대해 사용자보다 훨씬 더 많은 정보를 가지고 있다는 사실입니다.

GC.Collect()를 호출하려는 욕구는 일반적으로 다른 곳에서 저지른 실수를 은폐하려는 것입니다!

더 이상 필요하지 않은 물건을 잊고 처리하지 못한 곳을 찾으면 더 좋을 것입니다.

결론적으로, 애플리케이션을 프로파일링하고 이러한 추가 컬렉션이 사물에 어떤 영향을 미치는지 확인할 수 있습니다.프로필을 작성하지 않는 한 멀리 떨어져 있는 것이 좋습니다.GC는 자체적으로 처리되도록 설계되었으며 런타임이 발전함에 따라 효율성이 높아질 수 있습니다.작업을 방해하고 이러한 개선 사항을 활용하지 못할 수 있는 코드가 잔뜩 남아 있는 것을 원하지 않습니다.for 대신 foreach를 사용하는 것에 대한 유사한 주장이 있습니다. 즉, 향후 개선 사항을 foreach에 추가할 수 있으며 이를 활용하기 위해 코드를 변경할 필요가 없다는 것입니다.

.NET Framework 자체는 실시간 환경에서 실행되도록 설계되지 않았습니다.정말로 실시간 처리가 필요한 경우 .NET 기반이 아닌 내장형 실시간 언어를 사용하거나 Windows CE 장치에서 실행되는 .NET Compact Framework를 사용하면 됩니다.

최악의 상황은 프로그램을 잠시 정지시키는 것입니다.그러니 괜찮다면 그렇게 하세요.일반적으로 사용자 상호 작용이 대부분인 두꺼운 클라이언트나 웹 앱에는 필요하지 않습니다.

장기 실행 스레드가 있는 프로그램이나 일괄 프로그램이 개체를 올바르게 처리하더라도 OutOfMemory 예외가 발생하는 경우가 종종 있다는 것을 발견했습니다.제가 기억하는 것 중 하나는 업무용 데이터베이스 트랜잭션 처리였습니다.다른 하나는 씩(thick) 클라이언트 앱의 백그라운드 스레드에 대한 인덱싱 루틴이었습니다.

두 경우 모두 결과는 간단했습니다.GC가 없습니다. 메모리가 부족하여 지속적으로 수집됩니다.GC.Collect, 완벽한 성능.

나는 메모리 문제를 해결하기 위해 여러 번 시도했지만 소용이 없었습니다.나는 그것을 꺼냈다.

즉, 오류가 발생하지 않는 한 넣지 마십시오.넣어도 메모리 문제가 해결되지 않으면 다시 꺼내십시오.릴리스 모드에서 테스트하고 사과와 사과를 비교하는 것을 잊지 마십시오.

일이 잘못될 수 있는 유일한 경우는 당신이 그것에 대해 도덕적으로 생각할 때입니다.그것은 가치 문제가 아닙니다.많은 프로그래머가 코드에 불필요한 GC.Collect를 많이 포함하고 사망하여 곧장 천국으로 갔습니다.

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