런타임시 OutOfMemoryException에 대한 자세한 정보를 얻을 수있는 방법이 있습니까? 또는,이 예외는 어떻게 든 둘러싸인 try/catch에 의해 잡히지 않고 대신 try/catch가 호출 스택을 높일 수 있습니까? WinDBG를 사용하여 재현 할 수 없으므로 응용 프로그램에서 로그 할 수 있어야합니다.System.Drawing.Bitmap에서 OutOfMemoryException이 발생했습니다.
나는 긴 설명을 사과하지만, 설명 할만한 많은 원인이있다.
OutofMemoryException에 대한 모든 가능성을 읽고 기본적으로 모두 제거했습니다. 일반적으로 응용 프로그램은 훌륭하게 실행되지만 경우에 따라 특정 컴퓨터에서만 OutOfMemoryException이 발생합니다. 이 보고서는 현지에서 재현 할 수없는 분야이기 때문에 갈 로그 만 있습니다. 그러나 나는 상당한 양의 세부 사항을 가지고있다.
이상한 무엇인가 논리적으로 주변에 메모리를 할당 할 수
- 뭐든지 시도/캐치에 있지만 예외가 처리되지 않은으로 처리됩니다 (그리고 잡힌까지 더 높은 호출 스택)
- 사용중인 StringBuffers가 없습니다.
- 응용 프로그램을 다시 시작하고 다시 시작한 후에도 예외가 발생합니다.
- 몇 분만 지나면 예외가 발생하고 약 30MBi의 메모리가 할당되어 1.5MiB 이하의 청크가됩니다.
- 응용 프로그램 ("모든"프로세서 용으로 빌드 됨)이 64 비트로 실행되고 있음을 확인했습니다.
- 디스크 공간 (270Gb 사용 가능)이 부족하지 않고 페이지 파일이 사용 가능합니다.
- 은 가능한 LoH 단편화 문제가 아닌 것으로 보입니다.
최근 몇 차례이 응용 프로그램의 여러 부분에서 발생했습니다. 처음에는 System.Web.Serialization 어셈블리를 처음로드 할 때 예외가 발생했기 때문에 손상된 .NET 어셈블리가 있다고 결론을 내 렸습니다. 해당 어셈블리가 처음으로 사용 된 메서드 호출 중에 바로 발생하는 것으로 판단 할 수 있습니다. 컴퓨터를 원래대로 설정하고 Windows를 업데이트하면이 문제가 해결되었습니다.
그러나 며칠 내에 발생하는 두 번째 사례 인 다른 고객도 부패합니다. 이것은 어셈블리가로드되지 않는 위치에서 발생합니다. 나는 지금 첫 번째 오류를 재고하고있다. 알 수 있습니까 무엇 :
-
1MiB 파일이 다운로드됩니다. 이것은 MemoryStream으로 읽혀 지므로 2MiB만큼 클 수 있습니다. 그런 다음 System.Drawing.Bitmap 생성자에 공급되어 비트 맵이 약 8MiB가됩니다. 그러나, 그것은 모두 System.Exception을 잡는 try/catch에 있습니다. try/catch에없는 유일한 것은 byte [] 참조를 반환하는 것이며,이 참조는 메모리 할당이 아닌 참조 사본이어야합니다.
- 이 시간 전에 다른 중요한 메모리 할당이 수행되지 않았습니다. 동일하게 실행되어야하는 내 로컬 버전의 힙을 검토하면 응용 프로그램 아이콘과 Small Object Heap에있는 수십 개의 객체 만 표시됩니다.
- 특정 입력이있는 특정 시스템에서 반복 가능합니다. 그러나 이러한 시스템은 서로 복제됩니다.분명한 차이점은 Windows 업데이트 순서뿐입니다.
- 실행중인 어셈블리에 서명되어 있습니다. 체크섬이 손상되지 않았는지 확인하지 않습니까? 모든 시스템 어셈블리와 동일합니까? 이 인스턴스가 손상된 dll 또는 데이터로 설명 될 수있는 방법을 알지 못합니다.
- 예외 시간에 호출 스택을 보는 것은 의외로 도움이되지 않습니다. 아래 코드에서 예외가 발생하는 위치를 나타냅니다.
일부 COM 개체가 사용됩니다. 그러나, 정상적인 조건에서 우리는 메모리 문제없이 주 동안 응용 프로그램을 실행하고, 우리는 이러한 예외를 얻을 때, 그들은 단지 20 상대적으로 가벼운 COM 객체 (IUPnPDevice) 그래서
// Stack Trace indicates this method is throwing the OutOfMemoryException // It isn't CAUGHT here, though, so not in the try/catch. // internal void Render(int w, int h) { if (bitmap != null) { bitmap.Dispose(); bitmap = null; } if (!String.IsNullOrEmpty(url)) { // this information is printed successfully to log, with correct url // exception occurs sometime AFTER this somehow. Logger.Default.LogInfo("Loading {0}", url); // when file contents changed (to go from 1MiB to 500MiB, the error went away) byte[] data = DownloadBinaryFile(url); if (data != null) { try { Bitmap bmp; using (var ms = new MemoryStream(data)) { bmp = new Bitmap(ms); } bitmap = bmp; } catch (Exception) { // We do not catch anything here. Logger.Default.LogWarning("WARNING: Exception loading image {0}", url); } } // // if we had any errors, just skip this slide // if (bitmap == null) { return; } // QUESTION EDIT: // in the problematic version, there was actually an unnecessary // call here that turns out to be where the exception was raised: using(Graphics g = Graphics.FromImage(bitmap)) { } } } // calling this would trigger loading of the System.Web assembly, except // similar method has been called earlier that read everything. Only // class being used first time is the BinaryReader, which is in System.IO // and already loaded. internal static byte[] DownloadBinaryFile(String strURL, int timeout = 30000) { try { HttpWebRequest myWebRequest = HttpWebRequest.Create(strURL) as HttpWebRequest; myWebRequest.KeepAlive = true; myWebRequest.Timeout = timeout; myWebRequest.ReadWriteTimeout = timeout; myWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"; Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); using (HttpWebResponse myWebResponse = myWebRequest.GetResponse() as HttpWebResponse) { if (myWebResponse.StatusCode != HttpStatusCode.OK) { Logger.Default.LogWarning("WARNING: Response {0} loading {1}", myWebResponse.StatusCode, strURL); return null; } using (Stream receiveStream = myWebResponse.GetResponseStream()) { using (BinaryReader readStream = new BinaryReader(receiveStream)) { // this extension method uses MemoryStream, but seems irrelevant since we don't catch anything here. return readStream.ReadAllBytes(); } } } } catch (Exception e) { // we do not catch anything here. Logger.Default.LogError("ERROR: Exception {0} loading {1}", e.Message, strURL); } return null; }
사용 후 거의 즉각적 , 그 모든 후, 나는 개방 질문으로 돌아 간다. 내가 조사 할 수있는 OutOfMemoryException 객체에 대해 알려진 속성이 있거나 예외를 throw 한 후 호출하여이를 좁힐 수 있습니까?
And .. OutOfMemoryException이 첫 번째 try/catch에 의해 포착되지는 않지만 호출 스택 위로 더 잡히게되는 이유는 무엇입니까?
바이트 배열 (데이터) 때문에 mem 조각화가 발생할 수 있습니다. DownloadBinaryFile이 스트림을 반환하도록합니다. 데이터 크기에 따라 MemoryStream 또는 FileStream을 반환하도록 선택할 수 있습니다. –
스택 트레이스를 보여줄 수 있습니까? 이 문제는 조각화로 인해 발생할 수 있습니다. 가능한 해결 방법은 [https://stackoverflow.com/a/8564247/4684493](https://stackoverflow.com/a/8564247/4684493)을 참조하십시오. 또한 디버깅을 돕기 위해 [MemoryFailPoint] (https://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint.aspx)를 사용할 수도 있습니다. 결국 – Hintham
이 동의하면 조각화가 발생할 수 있습니다. 그러나 이것은 첫 번째 또는 두 번째 큰 힙 할당에서 발생합니다. –