728x90

만약 Nvidia 그래픽 카드를 사용하는 사람들 중에 하드디스크의 용량이 이상하게 작아져서 컴퓨터가 엄청 느려지거나, 어떠한 프로그램들이 실행이 되지 않는다면, Nvidia Geforce Experience가 설치 되어 있는지도 한번 확인을 해보자.


CPU의 점유율을 많이 잡아먹거나 C:\Users\my\AppData\Local\NVIDIA\NvBackend 경로에 backend.log 가 말도 안되게 큰 파일이 있을 수도 있다.


만약 이런 파일이 생겨있다면 가장 빠른 방법은 NVidia Geforce Experience를 삭제하는 것이 가장 빠른 방법이고, 


삭제하고 싶지 않다면 로그를 기록하는 기능을 비활성화 시켜야한다.

아래의 링크를 보고 따라하면 된다.

https://nvidia.custhelp.com/app/answers/detail/a_id/3171/~/how-to-enable-nvidia-graphics-driver-and-geforce-experience-installer-logging



728x90
728x90

여러 사람이 commit을 하다보니 한글 깨짐 현상이 발생하여 인터넷 검색 결과 3개의 설정을 변경해 주면 된다.



프로젝트 속성 -> 구성 속성 -> 일반 -> 문자 집합 : 유니코드 문자 집합 사용 (Debug, Release 전부)




도구 -> 옵션 -> 텍스트 편집기 -> 일반 -> 서명 없는 UTF-8 인코딩 자동 검색(D) 체크 해제




도구 -> 옵션 -> 환경 -> 문서->빨간 부분 체크 할 것.







출처 : https://m.blog.naver.com/PostView.nhn?blogId=yun4794&logNo=221084383612&proxyReferer=https%3A%2F%2Fwww.google.com%2F


http://www.sysnet.pe.kr/2/0/1349

728x90
728x90

DX11으로 개발한 프로그램이 내가 입사하기 전에 개발된거라서 DXSDK_JUN2010 을 설치해야 한다.


그런데 Windows 7 Ultimate K Service Pack1 사양에서 프로그램이 제대로 실행이 되지 않았다.







그래서 인터넷에서 D3DCOMPILER_47.dll을 다운받아서 실행을 했더니, 이번에는 이런 에러가 발생하면서 실행이 되지 않았다.





그래서 회사에 연락하여 프로그램을 개발 중인 PC에서 D3DCOMPILER_47.dll을 따로 받아서 넣었더니 바로 실행이 잘 되었다.


dll이 없다고 해서 아무거나 받아서 실행하지말고, 개발환경에 맞는 dll을 찾아서 넣어주는 것이 중요한 것 같다...




D3DCOMPILER_47.dll 이런 에러가 발생하는 건 나의 블로그 중에 DXSDK_Jun2010을 설치 하지 않아도 된다는 내용을 참조하면 처음부터 이 dll을 불러오지 않을 것 같다...


http://grandstayner.tistory.com/entry/DirectX11-Windows-8%EC%9D%B4%EC%83%81-%EB%B6%80%ED%84%B0%EB%8A%94-DXSDKJun10%EC%9D%84-%EC%84%A4%EC%B9%98-%ED%95%98%EC%A7%80-%EC%95%8A%EC%95%84%EB%8F%84-%EB%90%9C%EB%8B%A4-1?category=869475




- 위의 이미지는 같은 에러 메시지일 뿐 구글에서 동일한 에러 메세지의 이미지를 구해서 올린거다.

728x90
728x90

NDC 2012에 가서 들었던 내용인데...


우연히 PDF 발견


덤프 파일을 통한 사후 디버깅 실용 테크닉.pdf


728x90

'Basic Programming > C, C++' 카테고리의 다른 글

C++ - 60fps로 동작하게 하는 코드  (0) 2020.03.11
C++ - OutputDebugString()을 편하게 사용  (0) 2019.12.05
C++ - region, endregion  (0) 2018.08.03
C++ - Joystick 입력 받기.  (0) 2018.02.01
C++ - inline의 이해  (0) 2017.12.10
728x90
728x90

'Basic Programming > C++ 11' 카테고리의 다른 글

c++11 - atomic  (2) 2022.10.13
c++11 - constexpr  (0) 2018.08.22
C++11 - final, override 키워드  (0) 2017.09.18
C++11 - std::thread  (0) 2016.12.02
C++11 - "default" and "delete" keyword  (0) 2016.11.29
728x90

.NET Framework에서 새로운 클래스를 만들 때 여러가지 메모리 관리 디자인 패턴과 기법을 적용할 수 있지만, 한시적으로 사용해야 할 필요가 있는 자원들을 묶어서 관리할 때에는 IDisposable 패턴을 적극적으로 활용하는 것이 매우 유용합니다.

하지만 생각보다 IDisposable 패턴을 제대로 구현해서 사용하는 것은 쉽지 않으며 잘못 구현하기 쉽습니다.

이 아티클에서는 IDisposable 패턴을 구현하는 몇 가지 일반적인 전략들을 소개합니다. 잘못 설명된 부분이 있거나 보충이 필요한 부분은 댓글로 피드백을 자세히 남겨주시면 적극 반영하겠습니다.

IDisposable 인터페이스에 대한 이해

IDisposable 인터페이스가 제공하는 Dispose 메서드는 명시적이고 코드 작성자가 직접 호출할 수 있는 finalizer로, 이 메서드가 불리면 가비지 컬렉터에 의하여 나중에 호출되는 finalizer의 역할을 대체하도록 되어있습니다. 물론, 메모리 상에 할당된 메모리 블록의 해제까지 건너뛴다는 의미는 아닙니다.

그리고 무엇을 Dispose 메서드에서 제거해야 하는지 기준을 세운다면 객체에 대한 소유 권한을 정의하는 것이 필요합니다. 적어도 다음의 경우에는 확실히 Dispose 메서드 내에서 정리가 되어야 합니다.

  • 해당 객체를 Dispose 하게 되면 외부에서 더 이상 사용하는 것이 의미가 없는 객체 (예를 들어 클래스 내부에서 사용하던 파일 입출력 관련 객체, 비동기 작업을 위하여 만들어 놓은 스레드 관련 객체)
  • 외부에서 전달받은 객체이지만 객체의 생명 주기를 위탁하여 관리하도록 지정한 객체 (예를 들어 StreamReader나 StreamWriter가 객체 생성 시 인자로 Stream을 받는 사례)

가장 기본이 되는 IDisposable 구현 패턴

.NET 은 finalizer에 해당되는 멤버를 재정의할 수 있습니다. 하지만 finalizer가 언제 호출이 될 것인지 기약할 수 없으므로 이 finalizer를 대신하여 좀 더 이른 시기에 명시적으로 소멸자와 동등한 효과를 낼 수 있도록 만든 것이 바로 IDisposable.Dispose 메서드가 되겠습니다.

IDisposable 패턴을 처음 구현할 때에는 다음의 사항들이 핵심이 됩니다.

  • protected virtual void Dispose(bool disposing) 메서드를 추가합니다. sealed 클래스에 대해서는 private void Dispose(bool disposing)으로 바꾸어 정의합니다.
  • 객체가 dispose 처리가 이루어진 상태인지를 관리할 수 있는 boolean 필드를 하나 추가하고 이 필드는 기본값을 false로 설정합니다.
  • Dispose(bool disposing) 호출 시 다음의 로직을 구현합니다.
  • 만약 객체가 dispose 상태인 경우에는 함수를 종료합니다.
  • 객체가 dispose 상태임을 필드에 지정합니다. (true로 설정)
  • disposing 매개 변수의 상태와 관계없이 P/Invoke 등을 활용하여 메모리 할당을 받은 나머지 모든 리소스들에 대해 할당을 해제하는 코드를 추가합니다.
  • disposing 매개 변수가 true로 전달되는 경우는 명시적으로 Dispose 메서드를 호출한 경우이며, 이 때에 다른 모든 IDisposable을 구현하는 객체들을 Dispose 처리합니다.
  • IDisposable.Dispose 메서드 구현 시 Dispose(true)를 호출하고 finalizer 호출을 건너뛰기 위하여 GC.SuppressFinalize(this)를 호출합니다.
  • 소멸자에서는 Dispose(false)를 호출합니다.

다음은 코드 예시입니다.

public class DisposableSample : IDisposable
{
public DisposableSample()
{ }
    ~DisposableSample()
{
this.Dispose(false);
}

private bool disposed;
    public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
    protected virtual void Dispose(bool disposing)
{
if (this.disposed) return;
if (disposing)
{
// IDisposable 인터페이스를 구현하는 멤버들을 여기서 정리합니다.
}
// .NET Framework에 의하여 관리되지 않는 외부 리소스들을 여기서 정리합니다.
this.disposed = true;
}
}

IDisposable 객체의 컬렉션에 대한 소거

소켓, 스레드 풀, 혹은 커넥션 풀 같은 컬렉션을 객체 내부에 보관해야 하는 경우도 있습니다. 이러한 경우에도 컬렉션 내의 모든 IDisposable 객체에 대해서 정리를 하는 것이 필요합니다.

  • 컬 렉션 내의 모든 요소가 IDisposable 인터페이스를 구현하고 있다면 Dispose(bool disposing) 메서드에서 disposing이 true일 때 정리를 하면 됩니다. 그렇지 않은 경우, disposing 매개 변수의 상태에 무관하게 정리합니다.
  • Dispose 작업 도중 새로운 항목이 추가되는 것을 방지하기 위하여 disposed 필드를 확인하도록 하는 코드를 추가해야 할 수 있습니다.
  • 컬렉션 내의 모든 요소를 배열에 복사하여 Immutable Collection으로 변환한 다음 하나씩 방문하여 Dispose를 진행하고, 최종적으로 컬렉션의 요소들을 모두 제거합니다.

다음은 코드 예시입니다.

public class DisposableSample : IDisposable
{
public DisposableSample()
{
this.items = new List<IDisposable>();
}
    ~DisposableSample()
{
this.Dispose(false);
}

private bool disposed;
private List<IDipsosable> items;
    public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
    protected virtual void Dispose(bool disposing)
{
if (this.disposed) return;
if (disposing)
{
// IDisposable 인터페이스를 구현하는 멤버들을 여기서 정리합니다.
IDisposable[] targetList = new IDisposable[this.items.Count];
this.items.CopyTo(targetList);
foreach (IDisposable eachItem in targetList)
{
eachItem.Dispose();
}
this.items.Clear();
}
// .NET Framework에 의하여 관리되지 않는 외부 리소스들을 여기서 정리합니다.
this.disposed = true;
}
}

Dispose 메서드 내의 예외 처리

만약 Dispose 메서드를 실행하는 도중에 예외가 발생한다면, CA1065의 지침에 따라 명시적인 Dispose 호출이었든 아니었든 예외를 전파하지 않도록 처리하는 것이 필요합니다. 다만 명시적으로 Dispose를 호출하면서 예외가 발생했다면 예외를 전파하지 않는 대신 적절한 예외 처리는 필요합니다.

이 부분에 대한 자세한 내용은 https://msdn.microsoft.com/ko-kr/library/bb386039.aspx 페이지의 내용을 참고하시면 도움이 될 것입니다.

컬렉션 내의 모든 요소들을 Dispose 하는 코드를 조금 더 보강하면 다음과 같이 고쳐쓸 수 있겠습니다.

public class DisposableSample : IDisposable
{
public DisposableSample()
{
this.items = new List<IDisposable>();
}
    ~DisposableSample()
{
this.Dispose(false);
}
    private bool disposed;
private List<IDisposable> items;
    public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
    protected virtual void Dispose(bool disposing)
{
if (this.disposed) return;
try
{
if (disposing)
{
// IDisposable 인터페이스를 구현하는 멤버들을 여기서 정리합니다.
IDisposable[] targetList = new IDisposable[this.items.Count];
this.items.CopyTo(targetList);
foreach (IDisposable eachItem in targetList)
{
try { eachItem.Dispose(); }
catch (Exception ex) { /* 예외 처리를 수행합니다. */ }
finally { /* 정리 작업을 수행합니다. */ }
}
this.items.Clear();
}
try { /* .NET Framework에 의하여 관리되지 않는 외부 리소스들을 여기서 정리합니다. */ }
catch { /* 예외 처리를 수행합니다. */ }
finally
{
/* 정리 작업을 수행합니다. */
this.disposed = true;
}
}
finally { /* 정리 작업을 수행합니다. */ }
}
}

소유하고 있는 객체들에 대한 Dispose 또는 정리 작업들을 각각 try, catch, finally 블록안에 두어 예외가 발생하면 적절한 예외 처리를 할 수 있게 하고, Dispose 메서드 전체에 대해서 try, finally 블록 안에 두어 예외가 전파되지 않도록 하였습니다.

결론

.NET Framework 기반의 응용프로그램이 안정적으로 장시간 실행될 수 있게 만들어야 할 때 고려해야 할 요소들 가운데에서 가장 비중있게 다루어야 할 부분이 바로 메모리 관리입니다. IDisposable 인터페이스를 통한 명시적인 finalizer 호출은 적절하게 활용하면 응용프로그램의 메모리 관리를 단순하게 만드는데 큰 도움을 줍니다.


출처 : https://medium.com/rkttu/idisposable-%ED%8C%A8%ED%84%B4%EC%9D%98-%EC%98%AC%EB%B0%94%EB%A5%B8-%EA%B5%AC%ED%98%84-%EB%B0%A9%EB%B2%95-4fa0fcf0e67a

728x90

'Basic Programming > C#' 카테고리의 다른 글

C# - 작업 스케줄러에 등록하기  (0) 2021.12.10
C# - Steam Game 실행하기  (0) 2020.07.21
C# - WeakReference  (0) 2018.10.11
C# - 공부하기 좋은 사이트  (0) 2018.09.05
C# - Attibute  (0) 2018.07.09
728x90

WeakReference Class를 사용하여 메모리를 관리해보자. 


C#의 가장 큰 특징중 하나는 가비지 컬렉터(Garbage Collector)가 자동으로 메모리를 관리해준다는 것입니다.

상식적으로 가비지 컬렉터가 작동된다면 사용하지 않은 메모리는 자동으로 반환해야되지만

실제로 메모리가 반환되지 않고 계속 늘어나기도 합니다.


계속 늘어나는 메모리를 해제하고 싶지만 C#에는 따로 메모리를 해제하는 명령어가 없어서 메모리 릭(Memory leak)이 발생하기도 합니다.


이렇게 메모리가 계속 늘어나는 이유가 뭘까요?


가비지(Garbage)는 더 이상 참조가 없는 메모리를 뜻합니다.

메모리가 반환되지 않고 계속 늘어나고 있다면 어디선가 반환되야될 메모리를 의도치 않게 참조 하고 있어서 

가바지 컬렉터가 반환메모리로 인식하지 않아 청소를 못하고 자꾸 쌓이고만 있는것입니다.


저 또한 겪었던 문제로


하나의 UserControl을 만들었습니다.

이 UserControl은 DB에서 Select문으로 데이터를 끌어올때마다 생성하여 UserControl내부 로직을 타고 화면에 뿌려줍니다.

그 후 사용이 끝난 UserControl은 Dispose()를 해주지만 이상하게 검색을 할때마다 메모리가 늘어납니다.

결국 메모리 릭(Memory leak)이 발생하더군요.

저는 분명 모든 리소스를 해제했다고 생각하고 있었지만 어디선가 참조가 되고 있었는것이죠.

(결국 문제점을 발견하지 못했습니다. ㅠㅠ Garbage 강제 콜을 해도 메모리가 2%늘었다 1%줄었다 반복하더니 메모리 릭이 발생하더군요.)


이럴때 WeakReference Class를 사용해주면 됬었지만! 

그때 당시 저는 이 방법을 몰라서 한참을 돌아돌아 프로그램을 완성했었습니다.

(어찌했는지 기억도 잘 안나네요 ㅠㅠ)


WeakReference는 가바지 수집에 의한 개체 회수를 허용하면서 개체를 참조하는 일명 약한 참조를 만들어 냅니다.


아래 예제 소스를 보면서 설명하겠습니다.

(예제소스를 실행해보고 싶으시면 라벨 두개와 버튼 하나를 만들어서 복사후 연결만 시켜주면됩니다.)



<p>
using System;
using System.Windows.Forms;
 
namespace WeakReferenceTest
{
    public partial class WeakReference_Form : Form
    {
        stock phone;
        stock notebook;
        stock stock1;
        WeakReference stock2;
 
        public WeakReference_Form()
        {
            InitializeComponent();
            //Stock라는 클래스를 만들어 각각 Phone, NoteBook라는 물품을 담게 하였습니다.
            phone = new stock("Phone");
            notebook = new stock("NoteBook");
             
            //각각 참조를 거는데 phone은 일반적으로 사용하는 강한참조
            //notebook은 WeakReference를 이용한 약한 참조를 걸어보도록 하겠습니다.
            stock1 = phone;
            stock2 = new WeakReference(notebook);
 
            //각각 라벨에 출력해보겠습니다.
            labelControl1.Text = stock1 == null ? "null" : stock1.name;
            labelControl2.Text = stock2.Target == null ? "null" : (stock2.Target as stock).name;
 
            //당연한 이야기겠지만
            //------------  label1 = Phone
            //------------  label2 = NoteBook
            //가 출력됩니다.
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            //버튼 클릭시 phone과 notebook에 null을 넣어 초기화 시켜줍니다.
            phone = null;
            notebook = null;
 
            //가바지 컬렉터를 강제로 작동시켜보겠습니다.
            System.GC.Collect(0, GCCollectionMode.Forced);
            System.GC.WaitForFullGCComplete();
 
            //다시한번 참조한 값을 각각 라벨에 출력해보겠습니다.
            labelControl1.Text = stock1 == null ? "null" : stock1.name;
            labelControl2.Text = stock2.Target == null ? "null" : (stock2.Target as stock).name;
 
            //어떻게 나올지 예상하셨나요?
            //필자는 stock1과 stock2 모두 참조 객체가 null로 변경이 되었으니 null이 출력된다고 생각했습니다.
            //하지만 결과는
            //----------  label1 = Phone
            //----------  label2 = null
            //과 같이 출력됩니다.
            //강한참조는 참조 객체를 초기화 시켜도 Data를 붙잡고 있어서 메모리 회수가 안되는 것입니다.
        }
    }
 
    public class stock
    {
        public string name = "";
        public stock(string name)
        {
            this.name = name;
        }
    }
}
</p>


C#은 메모리를 컨트롤 안해도 된다는 생각을 가지고 있었지만 (필자가 배울때는 그렇게 배워서 ㅠㅠ)

실제로는 C나 C++만큼은 아니지만 메모리 관리를 해야된다고 생각합니다.


출처 : http://mirwebma.tistory.com/142

728x90

'Basic Programming > C#' 카테고리의 다른 글

C# - 작업 스케줄러에 등록하기  (0) 2021.12.10
C# - Steam Game 실행하기  (0) 2020.07.21
C# - Dispose  (0) 2018.10.12
C# - 공부하기 좋은 사이트  (0) 2018.09.05
C# - Attibute  (0) 2018.07.09
728x90
[in, out] 배열을 C#에서 C/C++로 넘기는 방법 - 두 번째 이야기



지난 글에 이어서.

[in, out] 배열을 C#에서 C/C++로 넘기는 방법
; http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&wid=810


마이크로소프트가 원래 의도한 바는 아니었겠지만, tlbimp.exe 의 기능을 보정할 수 있는 방법을 별도로 제공하고 있습니다.

.NET Framework Developer's Guide
- Customizing Runtime Callable Wrappers
; http://msdn.microsoft.com/en-us/library/e753eftz.aspx


위의 글에 포함된 그림이 재미있습니다. ^^

[그림 1: RCW DLL 생성 방법]
how_to_customize_rcw_1.gif

RCW를 생성하는 3가지 방법 중에서 중간 그림이 의미가 있는데, 일단 한번 tlbimp.exe에 의해서 생성된 DLL 을 역어셈블한 뒤, 원하는 데로 마샬링 정보를 바꾸고 다시 ilasm을 이용해서 DLL을 생성하고 있습니다. 오호... 이 정도면 훌륭한 대안이죠. ^^




이것을 이용해서 지난 번 예제를 개선해 보겠습니다.

IDL 은 원래 정의된 그대로 사용하고,

[
	object,
	uuid(1A38076B-3D6D-4F20-8B4D-C72EF6AE1204),
	dual,
	nonextensible,
	helpstring("IMyTest Interface"),
	pointer_default(unique)
]
interface IMyTest : IDispatch
{
	[id(0x3003), helpstring("method PrepareBuf")] 
	HRESULT PrepareBuf([in, out, size_is(bufLength)] __int64 buffer [], [in] int bufLength);
};


마샬링 정보가 올바르진 않겠지만 일단 tlbimp.exe (또는 Visual Studio의 DLL 참조)를 이용하여 interop DLL을 생성합니다.

tlbimp testatl.dll /out:interop.testatl.dll


ildasm 으로 DLL을 역어셈블하면 해당 메서드가 다음과 같이 선언된 것을 볼 수 있습니다.

ildasm interop.testatl.dll /out:interop.testatl.il

.method public hidebysig newslot virtual 
      instance void  PrepareBuf([in][out] int64& buffer,
                                 [in] int32 bufLength) runtime managed internalcall
{
.custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 03 30 00 00 00 00 )   // ...0....
.override interop.testatl.IMyTest::PrepareBuf
} // end of method MyTestClass::PrepareBuf


여기에서 "[in][out] int64& buffer" 구문을 "[in][out] int64[] marshal([]) buffer" 과 같이 바꿔줍니다. (또 한군데 더 정의되어 있기 때문에 그 부분도 마저 바꿔줍니다.) 이렇게 변경하고 다시 ilasm으로 어셈블해주면, C# 에서 정상적으로 long [] 으로 사용할 수 있습니다.

ilasm interop.testatl.il /dll

public virtual void PrepareBuf(long[] buffer, int bufLength);


우와~~~ ^^ 깔끔하죠! (첨부된 파일은 위의 예제와 지난 번 글의 예제를 함께 테스트한 프로젝트입니다.)

그러고 보니, 이걸 하면서 예전에 쓴 글이 하나 생각났습니다.

COM 개체의 이벤트를 구독하는 코드 제작
; http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&wid=589


위의 방법 역시 interop DLL 코드가 잘못 생성된 경우인데, ildasm/ilasm 조합으로 해결할 수도 있었지 않았을까 싶네요. ^^


출처 : http://www.sysnet.pe.kr/2/0/811


728x90

+ Recent posts