[c#] 루프 중에 TextBox.Text에 추가하면 반복 할 때마다 더 많은 메모리를 차지하는 이유는 무엇입니까?
짧은 질문
180,000 번 실행되는 루프가 있습니다. 각 반복이 끝날 때 실시간으로 업데이트되는 TextBox에 결과를 추가해야합니다.
를 사용 MyTextBox.Text += someValue
하면 응용 프로그램이 엄청난 양의 메모리를 사용하게되며 수천 개의 레코드를 사용하면 사용 가능한 메모리가 부족합니다.
TextBox.Text
180,000 번에 텍스트를 추가하는 더 효율적인 방법이 있습니까?
편집 나는이 특정 경우의 결과에 대해 정말로 신경 쓰지 않지만 이것이 메모리 돼지 인 것처럼 보이는 이유와 TextBox에 텍스트를 추가하는 더 효율적인 방법이 있는지 알고 싶습니다.
긴 (원본) 질문
CSV 파일의 ID 번호 목록을 읽고 각각에 대한 PDF 보고서를 생성하는 작은 앱이 있습니다. 각 pdf 파일이 생성 된 후에 ResultsTextBox.Text
는 처리되고 성공적으로 처리 된 보고서의 ID 번호가 추가됩니다. 프로세스는 백그라운드 스레드에서 실행되므로 ResultsTextBox는 항목이 처리 될 때 실시간으로 업데이트됩니다.
현재 180,000 개의 ID 번호에 대해 앱을 실행하고 있지만 시간이 지남에 따라 애플리케이션이 차지하는 메모리는 기하 급수적으로 증가하고 있습니다. 약 90K에서 시작하지만 약 3000 개 레코드가 약 250MB를 차지하고 4000 개 레코드가 애플리케이션이 약 500MB의 메모리를 차지합니다.
Results TextBox에 대한 업데이트를 주석 처리하면 메모리가 약 90K에서 상대적으로 고정되어 있으므로 쓰기 ResultsText.Text += someValue
가 메모리를 먹는 원인 이라고 가정 할 수 있습니다 .
제 질문은 왜 이래요? 메모리를 차지하지 않는 TextBox.Text에 데이터를 추가하는 더 좋은 방법은 무엇입니까?
내 코드는 다음과 같습니다.
try
{
report.SetParameterValue("Id", id);
report.ExportToDisk(ExportFormatType.PortableDocFormat,
string.Format(@"{0}\{1}.pdf", new object[] { outputLocation, id}));
// ResultsText.Text += string.Format("Exported {0}\r\n", id);
}
catch (Exception ex)
{
ErrorsText.Text += string.Format("Failed to export {0}: {1}\r\n",
new object[] { id, ex.Message });
}
또한 앱이 일회성이며 모든 보고서를 생성하는 데 몇 시간 (또는 며칠)이 걸리는 것은 중요하지 않다는 점도 언급 할 가치가 있습니다. 내 주요 관심사는 시스템 메모리 제한에 도달하면 실행이 중지된다는 것입니다.
이 작업을 실행하기 위해 주석 처리 된 결과 TextBox를 업데이트하는 줄을 그대로 두어도 괜찮지 만 TextBox.Text
향후 프로젝트를 위해에 데이터를 추가하는 메모리 효율적인 방법이 있는지 알고 싶습니다 .
답변
메모리 사용량이 너무 큰 이유는 텍스트 상자가 스택을 유지하여 사용자가 텍스트를 실행 취소 / 다시 실행할 수 있기 때문이라고 생각합니다. 해당 기능은 귀하의 경우에 필요하지 않은 것 같으므로 IsUndoEnabled
false로 설정하십시오 .
답변
사용 TextBox.AppendText(someValue)
대신에 TextBox.Text += someValue
. TextBox.Text가 아닌 TextBox에 있기 때문에 놓치기 쉽습니다. StringBuilder와 마찬가지로 이것은 무언가를 추가 할 때마다 전체 텍스트의 복사본을 만드는 것을 방지합니다.
이것이 IsUndoEnabled
keyboardP의 답변 의 플래그와 어떻게 비교되는지 보는 것은 흥미로울 것입니다.
답변
text 속성에 직접 추가하지 마십시오. 추가를 위해 StringBuilder를 사용하고 완료되면 .text를 stringbuilder의 완성 된 문자열로 설정합니다.
답변
텍스트 상자를 사용하는 대신 다음을 수행합니다.
- 만일을 대비하여 텍스트 파일을 열고 오류를 로그 파일로 스트리밍하십시오.
- 목록 상자 컨트롤을 사용하여 오류를 표시하여 잠재적으로 대량의 문자열을 복사하지 않도록합니다.
답변
개인적으로 저는 항상 string.Concat
*를 사용 합니다. 나는 일반적으로 사용되는 방법을 비교하는 프로파일 링 통계를 가지고있는 Stack Overflow에서 몇 년 전에 여기에서 질문을 읽은 것을 기억 string.Concat
합니다.
그럼에도 불구하고 내가 찾을 수있는 최선은 이 참조 질문 과 내부적으로 를 사용하는 것을 언급하는 이 특정 String.Format
대StringBuilder
질문 입니다. 이것은 당신의 기억력이 다른 곳에 있는지 궁금합니다.String.Format
StringBuilder
** James의 의견에 따르면 웹 기반 개발에 중점을두기 때문에 무거운 문자열 형식을 지정하지 않는다는 점을 언급해야합니다. *
답변
TextBox를 재고 할 수 있습니까? String Items를 보유한 ListBox는 아마도 더 잘 수행 될 것입니다.
그러나 주된 문제는 요구 사항 인 것 같습니다. 180,000 개의 항목을 표시하는 것은 (인간) 사용자를 겨냥 할 수 없으며 “실시간”에서 변경하는 것도 아닙니다.
바람직한 방법은 데이터 샘플 또는 진행률 표시기를 표시하는 것입니다.
가난한 사용자에게 덤프하고 싶을 때 배치 문자열이 업데이트됩니다. 어떤 사용자도 초당 2 ~ 3 개 이상의 변경 내용을 설명 할 수 없습니다. 따라서 초당 100 개를 생산한다면 50 개 그룹을 만드십시오.
답변
일부 응답은 이에 대해 암시했지만 아무도 놀라움을 표명하지 않았습니다. 문자열은 변경 불가능합니다. 즉, 생성 된 후에는 문자열을 수정할 수 없습니다. 따라서 기존 문자열에 연결할 때마다 새 문자열 개체를 만들어야합니다. 해당 문자열 개체와 관련된 메모리도 분명히 만들어야하는데, 문자열이 점점 커질수록 비용이 많이들 수 있습니다. 대학에서 저는 한때 Huffman 코딩 압축을 수행하는 Java 프로그램에서 문자열을 연결하는 아마추어 실수를 저질렀습니다. 매우 많은 양의 텍스트를 연결하는 경우 여기에 언급 된 일부에서 언급했듯이 단순히 StringBuilder를 사용할 수 있었을 때 문자열 연결이 실제로 당신을 해칠 수 있습니다.
