티스토리 뷰

C#

메모리 스트림 사용에 관해

takim 2021. 10. 19. 10:26

에러 발생!!

 

 

작년 2020.12 경에 해외출장을 가게 되었습니다.

기존에 있던 장비에서 신규장비로 바꾼 뒤 프로그램 변경을 했었는데 

프로그램 변경 했던 인원이 해외출장 못가는 상황이라 제가 가게 되었습니다.

헝가리에 도착하여 에러 하나를 보았습니다.

 

Out of Memory Exception

이 문구를 보고 Visual Studio의 프로파일링 도구를 활용해서 캡처하는 방식으로

찾아내 보려고 했습니다.

 

삽질 이야기

 

그 때 당시 장비 설치하고 1주 이내로 제품 생산을 진행해야하는데

1시간 가동하면 메모리 관련 예외가 발생 했었습니다.

그러면서 Visual Studio가 32bit이라 제가 사용하는 응용 프로그램은 64여도 메모리 사용에 제한이

있었던 것 같았습니다. Debug모드로 할때는 확실했고 Release 모드는 실행할 때 코드를 디버깅 할 거냐고 묻는데 이 때 

디버깅 한다고 하면 32Bit로 래핑 되는 것 같은 느낌이 들었습니다.

그래서 Release 모드로 빌드하고 난 뒤 Visual Studio에서 실행하는게 아닌

응용 프로그램을 직접 실행 시키니 2시간 까지는 버티는 모습을 보았습니다.

이것과 관련해서는 나중에 stackoverflow에 질문글이 있길래 알려주면서 개념을 다 잡았었습니다.

 

이렇게 하다가 근본적인 문제가 이것이 아니라는 것이라 생각하게되었고

왜 안되는지에 관해 고민해 보기 시작했습니다.

 

-현재 발생 에러

>Out of Memory Exception

-기존 설비 존재 유무

>존재

-기존 설비의 프로그램 사용 가능한지

>불가

-왜 불가한지

>기존 설비는 Mako 카메라를 사용하였고 현재 설비는 Basler 카메라를 사용 중

-카메라를 왜 바꾸었는가

>이미지 품질이 더 좋기 때문에

 

이렇게 생각하다보니 카메라에서 이미지 취득하는 부분과 연관되어 있다고 생각하게 되었습니다.

그래서, 가장 의심 되는 이미지 저장 관련부터 확인 했습니다.

이미지 저장을 안 할 경우 어떻게 되는지 확인 하니 2시간30분에서 3시간까지 버티는 모습을 보여주었습니다.

그런데, 이미지 저장을 안하는데도 버티는 시간이 없어지지 않는다면

이미지 저장 문제라고 볼 수 없었습니다.

 

그래서 이미지 취득과정에 관해 기존 코드와 현재 코드를 병행하여 확인했습니다.

그래서 확인한 것이 '메모리 스트림' 입니다.

 

메모리 스트림에 byte array가 활용되는데 연속적인 주소가 없어서 생긴 에러 였습니다.

네.... 알고 나니 별거 아닌 거였습니다....

 

먼저 그때 당시 정리한 내용을 캡처 해 보았습니다.

 

 

에러 확인

 

> 메모리 스트림을 사용하는 곳이었습니다.

 

 

 

> 기존 설비 코드에는 ByteToBitmap을 사용했었는데 신규 설비에는 ByteToBitmapImage를 사용해서 

아웃풋 타입이 달랐습니다.

 

> 그 때 당시 제작 해준 동료에게 해당 내용 공유하였고 굳이 BitmapSource를 사용 했던 이유를 물어 보았습니다.

물론 저 이유 말고도 성능 개선을 위해 영상처리 작업전에 이미지를 스탠바이 시켜두려고 BitmapSource로 한 이유도 있었습니다. 

 

[참고한 링크]

https://www.codeproject.com/Articles/348590/A-replacement-for-MemoryStream

 

A replacement for MemoryStream

Explains the cause of the OutOfMemoryExceptions which commonly occur when using MemoryStream, and introduces a replacement which uses a dynamic list of memory segments as a backing store, as opposed to a single array, making it more resilient with large da

www.codeproject.com

 

 

 

> 이걸 어떻게 설명을 해야할까라는 생각으로 만들어 본 자료입니다.

어떻게 전달해야 잘 전달할 수 있을지 아직도 어렵고 잘 모르겠습니다.

지금 위 사진을 보니 한눈에 딱 알수 없을 것 같기도 합니다.

 

 

> 에러 확인하던 와중에 Bitmap은 가비지 콜렉터가 관리하지 않는건가? 하는 생각도 했었습니다.

마샬링을 할때는 주의해야겠단 생각이 들었습니다.

 

 

> GC(2)를 하면 더 좋은 건줄 알고 GC(2)를 자주 하자! 라는 이야기를 설파했는데 

알고보니 GC 자체를 하는게 성능상 불리할 수도 있다는 의견들이 많더라구요 가비지 콜렉터가 알아서 수집을 하게 두고 저는 어떤 방식으로 수집을 하는지 명확히 이해한 뒤 최대한 GC(0)에서 수집이 가능하도록 만들어 나가야 한다는 생각을 하고 있습니다. 

그래서 요즘은 전역변수 쓰는게 많이 두렵더라구요.

 

 

> 이때까지만해도 VS를 64비트로 지원할지 꿈에도 몰랐습니다. 

 

 

> 64비트 지원은 정말 좋았습니다. Xamarin 이나 WPF, UWP 등 MS의 행보가 너무 제가 생각하는 좋은 방향으로 흘러가고 있고 VS도 절대 지원하지 않을 것 같던 64비트로 만들어준게 너무 좋았습니다.

MS 짱짱맨

 

 

> 이것에 대해 정리하고 있을 때 stackoverflow에 질문글을 보다가

제가 알것 같은 내용이 있어 답변 해 준것이 있습니다.

 

Visual Studio 도구 중에 QuickWatch라는 것을 사용해서 변수의 값을 보는데 

64Bit로 빌드 했는데 퀵와치 도구로 확인 할 때는 값이 다르게 나오는 경우를 두고

왜 이런 소수점 에러가 발생하는지 의문을 가지는 것으로 보았습니다.

 

결국엔 QuickWatch가 32Bit라서 그런 것이었습니다.

 

 

[링크]

https://stackoverflow.com/questions/65490353/runtime-float-calculation-vs-evaluated-calculation/65491074#65491074

 

 

 

마치며

 

 

메모리스트림 부터 시작해서 VS의 환경까지 알 수 있는 좋은 삽질이었던 것 같습니다.

물론 1년 전 그 때는 GC의 개념을 잘못 이해하고 있었지만 시간이 지나다 다시 잘못된 부분을

보충하여 괜찮지 않을까 합니다.

지금 제가 정리한 것도 오류가 있을 수도 있으나 오류를 인지하고 난 다음 지속적으로 고쳐나가야죠!

'C#' 카테고리의 다른 글

폴더관리 프로그램  (0) 2022.10.20
Task와 Thread와 BackgroundWorker의 관해서  (2) 2021.09.02
Task 관련 테스트  (0) 2021.07.20
C# - BackgroundWorker에 관하여  (0) 2021.06.28
C#의 역사  (0) 2021.06.20
댓글