|
메모리 단편화 문제가 있었네요.. 함수내에서 new로 하지않고
멤버 char배열을 만들어 사용하도록 바꿨습니다.
AnsiString타입인 ReceiveBuf는 memo 추가할 때 사용하려고 만든것인데
앞으로는 memo 추가할 때 직접 멤버char배열을 사용하도록 바꿔야 할 것 같습니다.
정말 많은 도움이 됐고요 감사드립니다.
열씸! 님이 쓰신 글 :
: COM port제어시 특정한 에러가 나지 않고 CPU사용율이 100%가 되는 경우는
: 대개가 CriticalSection의 할당이나 기타 자원할당등의 이벤트를 기다리는 코드가 무한반복되는 경우입니다.
: 해당 컴포넌트가 안정적인 녀석인진 써보지 않아서 잘 모르겠구요.
: 낡은 RS232c 나 USB 제어 컴포넌트들은 Thread safe하지 않은 코드들이 난무하는터라 신뢰하지 않습니다.
:
: 아래의 코드에도 좀 이상한 부분들이 있군요.
: ReceiveBuf = (char *)pBuffer; <- pBuffer는 char *타잎인데도 char *로 캐스팅하고 계시군요 쓸모없습니다.
:
: if(ReceiveBuf2!= "") <- ReceiveBuf2가 AnsiString 타잎처럼 문자열 비교연산을 특별히 지원하지 않는다면
: 당연히 pBuffer 는 지역변수인 스택에 위치하고 "" 인 NULL Terminated String은 리터럴 영역에 존재하거나
: 설정에 따라 특정 주소값에 할당되어 있을것이므로 항상 true가 되는 구문입니다.
: 즉 strcmp 함수를 쓰시거나 AnsiString 타잎으로 캐스팅(원래 AnsiString 타잎이었다면 문제 없습니다)
: 하셔야 할겁니다. (사실 이경우 *pBuffer != NULL 한방이면 끝나는거였습니다.)
: 그리고 문제가 되는게
: pBuffer를 동적 할당하고 계신데,
: 동적할당후 해제 전에 Memo컴포넌트에 내용을 업데이트 하고 계신걸로 보이는군요.
: 이게 두 가지 문제가 있습니다.
: 만약 이 ApdComPort1TriggerAvail 함수가 쓰레드로 부터 호출되는 구조라면(Callback처럼)
: VCL 컴포넌트들은 ThreadSafe하지 않으므로, Synchronize같은 함수를 통해 호출되었어야 합니다.
: 이부분은 사용하시는 ApdComPort 의 메뉴얼을 보시던가, 아니면 알 수 없는 부분이지만,
: 메모장같은게 아닌 파일로 덤프하시거나 하는 방법으로 VCL사용을 배제해 보시고 에러가 나지 않는다면
: VCL ThreadFailure 라고 보시면 되겠죠.
: 또 한가지 문제는, Memory Fragmentation 입니다.
: 버퍼할당후 VCL에 업데이트 했다는 말은,
: VCL 컴포넌트에 (메모장) 문자열이 추가되었단 말이고, 그 말은 메모리의 또다른 동적 할당을 의미하죠.
: 즉 [pBuffer할당메모리][ Memo할당메모리] 이런 구조로 힙영역에 적재 될꺼란겁니다.
: 그 후 메모는 해제 되지 않은채 pBuffer는 delete되고 있는 구조죠
: 즉, [해제된 사용가능영역][Memo할당메모리] 처럼 되는데
: 이렇게 짜실 짜실하게 해제된 영역과 할당된 영역이 스트라이핑 되는 경우,
: 이미 해제된 사용가능영역보다 큰 메모리는 할당 불가가 되는 사태가 생길 수 있습니다.
: 즉, 전체 메모리가 1기가가 남았다 하더라도
: 1바이트씩 사이사이에 Memo장에 할당된 문자들이 끼어서
: 조각난 사용가능 메모리의 크기가 1메가 단위라면,
: 1메가 이상되는 메모리는 할당할 수 없는 메모리 단편화 문제가 생긴다는겁니다.
: 이런 경우, pBuffer를 미리 스택에서 크기를 고정해 놓고 사용하고,
: 그 크기보다 크게 들어오는 경우 계속 잘라서 메모에 덤프 시키는 식으로 전환하시는게
: 안전한 방법이실겁니다.
: 스택에다가 메모리를 할당한다는것은, 별도의 할당 메카니즘이 있다기 보다,
: 스택포인터의 위치를 끌어올리는 단 한번의 대입으로 완료되는 메카니즘이므로,
: 성능도 올라가게 됩니다.
: 크기를 예측할 수 없을때 동적할당을 쓰곤 하시는데...
: 어차피 시스템에서 사용할 수 있는 메모리의 양은 제한이 있으므로 메모리풀을 만드는 방법이
: 더 좋은 해결책이 되겠죠.
: 그게 귀찮으면 스택으로 가는겁니다.
:
:
:
:
: 조윤상 님이 쓰신 글 :
: : 안녕하세요...
: : 제가 Async Pro ApdComPort를 이용해서 Terminal을 만들었는데요
: : 사용 중 문제가 있어 질문드립니다.
: :
: : 장비2대가 연결되있고 PC는 한대입니다.
: : PC에 Terminal창 두개 만들고 ApdComPort도 두개 만들었는데 실행중 문제가
: : 있습니다.
: :
: : 문제1.
: : 처음 실행후 얼마동안은 작동이 잘되다가 어느순간 Terminal화면이 멈춰버리고
: : 키도 입력이 안됩니다. 그러다 끊고 다시 연결하면 또 잘됩니다.
: :
: : 문제2.
: : 어느순간 CPU사용률이 100%되면서 프로그램이 죽어있는것처럼 됩니다.
: :
: : 제 생각에는 콤포넌트 내부Buffer를 사용하면서 지우지 않아서 생기는 현상 같습니다.
: : 혹시 몰라 소스첨부합니다.
: :
: : //장비1의 TriggerAvail이벤트 함수:
: : void __fastcall TMrTerminalMainForm::ApdComPort1TriggerAvail(TObject *CP,
: : WORD Count)
: : {
: : char* pBuffer ;
: :
: : try
: : {
: : ReceiveBufLen = Count;
: : if(ReceiveBufLen <= 0 )
: : {
: : ApdComPort1->Open = false;
: : return;
: : }
: : pBuffer = new char[Count] ;
: : memset(pBuffer, 0, sizeof(pBuffer));
: :
: : for (int i=0;i<Count;i++)
: : {
: : pBuffer[i] = ApdComPort1->GetChar();
: : }
: :
: : ReceiveBuf = (char *)pBuffer;
: :
: : if(ReceiveBuf != "") //if(pBuffer != NULL)
: : AddToMemo();
: : }
: : __finally
: : {
: : delete[] pBuffer;
: : }
: : }
: : //---------------------------------------------------------------------------
: :
: : //장비2의 TriggerAvail이벤트 함수:
: : void __fastcall TMrTerminalMainForm::ApdComPort2TriggerAvail(TObject *CP,
: : WORD Count)
: : {
: : char* pBuffer2;
: :
: : try
: : {
: :
: : ReceiveBufLen2= Count;
: :
: : if(ReceiveBufLen2<= 0 )
: : {
: : ApdComPort2->Open = false;
: : return;
: : }
: : pBuffer2= new char[Count] ;
: :
: : memset(pBuffer2, 0, sizeof(pBuffer2));
: :
: : for (int i=0;i<Count;i++)
: : {
: : pBuffer2[i] = ApdComPort2->GetChar();
: : }
: :
: : ReceiveBuf2= (char *)pBuffer2;
: :
: : if(ReceiveBuf2!= "")
: : AddToMemo2();
: :
: : }
: : __finally
: : {
: : delete[] pBuffer2;
: : }
: :
: : }
: : //---------------------------------------------------------------------------
|