본 내용은 크로스 플랫폼 개발을 위한 C#10과 .NET 6 Sixth Edition(김현욱 옮김 마크프라이스 지음)의 책을 토대로 공부한 내용을 요약 정리하는 것입니다.
String 연산에 대해 일반적으로 +나 substring, concat등을 사용하는데 StringBuilder는 본 책을 보고 알게되었다.
본 페이지에서는 앞서 언급한 +, concat등의 방법과 StringBuilder를 사용한 방법중 어떤 방법이 더 효율적인지 메모리 측면에서 비교해본 내용이다.
본 페이지에서는 경과시간과 리소스 사용량을 쉽게 모니터링 할 수 있는 Recorder 클래스를 구현을 먼저한다.
Recorder class를 구현하기 위해 Stopwatch, Process 클래스를 이용한다.
본 책에 Stopwatch와 Process 클래스의 다음 멤버를 소개한다.
Stopwatch | |
Restart | 시간을 0으로 리셋, 타이머를 시작 |
Stop | 타이머 정지 |
Elapsed | 경과시간을 TimeSpan 포맷(hours:minutes:seconds)로 저장 |
ElapsedMiliseconds | 경과시간을 int64 형식의 ms값으로 저장 |
Process | |
VirtualMemorySize64 | 프로세스에 할당된 가상 메모리를 바이트로 표현 |
WorkingSet64 | 프로세스에 할당된 물리 메모리를 바이트로 표시 |
Recorder클래스는 다음과 같이 구현할 수 있다.
- 클래스를 일반 함수와 같이 사용하기 위해 Static으로 선언했다.
- Start함수가 시작되면 물리메모리와 가상메모리를 각각 bytesPhysicalBefore, bytesVirtualBefore 에 저장한다.
- Stop함수가 시작되면 그 시점의 물리, 가상메모리를 bytesPhysicalAfter, bytesVirtual After에 저장한다.
- 그리고 After - before로 사용된 메모리를 측정하여 플랏한다.
using System.Diagnostics; // Stopwatch
using static System.Console;
using static System.Diagnostics.Process; // GetCurrentProcess()
namespace Packt.Shared;
public static class Recorder
{
private static Stopwatch timer = new();
private static long bytesPhysicalBefore = 0;
private static long bytesVirtualBefore = 0;
public static void Start()
{
// force two garbage collections to release memory that is no
// longer referenced but has not been released yet
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// store the current physical and virtual memory use
bytesPhysicalBefore = GetCurrentProcess().WorkingSet64;
bytesVirtualBefore = GetCurrentProcess().VirtualMemorySize64;
timer.Restart();
}
public static void Stop()
{
timer.Stop();
long bytesPhysicalAfter = GetCurrentProcess().WorkingSet64;
long bytesVirtualAfter = GetCurrentProcess().VirtualMemorySize64;
WriteLine("{0:N0} physical bytes used.",
bytesPhysicalAfter - bytesPhysicalBefore);
WriteLine("{0:N0} virtual bytes used.",
bytesVirtualAfter - bytesVirtualBefore);
WriteLine("{0} time span elapsed.", timer.Elapsed);
WriteLine("{0:N0} total milliseconds elapsed.",
timer.ElapsedMilliseconds);
}
}
진입점인 Program.cs에 다음의 코드를 작성한다.
+를 사용하여 int를 string으로 연결하는것과 StringBuilder를 이용하여 연결하는 차이다.
int[] numbers = Enumerable.Range(
start: 1, count: 50_000).ToArray();
WriteLine("Using string with +");
Recorder.Start();
string s = string.Empty; // i.e. "";
for (int i = 0; i < numbers.Length; i++)
{
s += numbers[i] + ", ";
}
Recorder.Stop();
WriteLine("Using StringBuilder");
Recorder.Start();
System.Text.StringBuilder builder = new();
for (int i = 0; i < numbers.Length; i++)
{
builder.Append(numbers[i]);
builder.Append(", ");
}
Recorder.Stop();
결과적으로 하기가 표시된다.
사용된 물리 메모리 및 가상메모리, 소요시간을 비교 시 StringBuilder가 압도적으로 좋다.
왜 몰랐지???