728x90
    
    
  📘 Chapter 3.5: 코드 분석 및 성능 측정 도구 사용 (BenchmarkDotNet 등)
✅ 이 챕터에서 배울 것
- 왜 성능 측정이 중요한가
- BenchmarkDotNet 사용법 (실전 예제 포함)
- 간단한 Stopwatch 성능 측정 방법
- GC, Memory 관련 측정
- 실무 상황에서 벤치마크 전략
- 예: for vs foreach, StringBuilder vs +
1️⃣ 왜 성능 측정이 중요한가?
"느릴 것 같아서 바꿨는데, 더 느려짐"
→ 실무에서 흔한 일이다
✅ 체감 성능 ≠ 실제 성능
- 컴파일러 최적화
- GC 개입
- JIT 예열 등으로 오차 생김
→ 그러니까 정확한 측정 도구로 정량 분석해야 된다!
2️⃣ BenchmarkDotNet – .NET 성능 측정의 정석
✅ 설치
dotnet add package BenchmarkDotNet✅ 기본 템플릿 예제
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
public class MyBenchmark
{
    private List<int> _list = Enumerable.Range(0, 1000).ToList();
    [Benchmark]
    public void ForLoop()
    {
        for (int i = 0; i < _list.Count; i++)
        {
            var val = _list[i];
        }
    }
    [Benchmark]
    public void ForeachLoop()
    {
        foreach (var item in _list)
        {
            var val = item;
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        BenchmarkRunner.Run<MyBenchmark>();
    }
}
✅ 실행하면 bin/Release/netX.X/BenchmarkDotNet.Artifacts 안에 결과 출력됨!
🔍 결과 예시
| Method | Mean | Error | Gen 0 | Allocated | 
|---|---|---|---|---|
| ForLoop | 2.345 us | ±0.005 | 0.00 | 0 B | 
| ForeachLoop | 2.158 us | ±0.004 | 0.00 | 0 B | 
➡️ 오차 범위까지 포함된 정밀 결과 제공
➡️ GC 할당도 확인 가능!
3️⃣ 간단한 측정: Stopwatch
var sw = Stopwatch.StartNew();
for (int i = 0; i < 1000000; i++)
{
    var x = i * 2;
}
sw.Stop();
Console.WriteLine($"⏱ 실행 시간: {sw.ElapsedMilliseconds} ms");
🟡 간단하지만:
- GC 개입
- 최적화 여부
- Warm-up 안 됨
→ 정확한 비교용으론 BenchmarkDotNet이 낫다!
4️⃣ 실전: StringBuilder vs 문자열 +
public class StringBenchmark
{
    [Benchmark]
    public string StringPlus()
    {
        string result = "";
        for (int i = 0; i < 100; i++)
        {
            result += i;
        }
        return result;
    }
    [Benchmark]
    public string UseStringBuilder()
    {
        var sb = new StringBuilder();
        for (int i = 0; i < 100; i++)
        {
            sb.Append(i);
        }
        return sb.ToString();
    }
}
✅ 대부분의 경우 StringBuilder가 훨씬 빠르다
하지만 반복 횟수가 작으면 큰 차이 안 나기도 한다
5️⃣ GC, 메모리 측정도 가능
[MemoryDiagnoser]
public class GCBenchmark
{
    [Benchmark]
    public void AllocateList()
    {
        var list = new List<int>();
        for (int i = 0; i < 1000; i++)
        {
            list.Add(i);
        }
    }
}
📌 출력에 Gen0, Gen1, Allocated 값까지 포함됨
✅ 실무 팁: 벤치마크 전략
| 상황 | 전략 | 
|---|---|
| 성능 비교 | 반드시 BenchmarkDotNet으로 테스트 | 
| GC 개입 확인 | [MemoryDiagnoser] 어노테이션 추가 | 
| 반복 횟수 적정화 | 실제 사용 상황과 유사하게 | 
| 결과 해석 | 평균 + 표준편차 함께 보기 | 
| Warm-up | 초기 1~2회 측정값은 버리는게 좋음 | 
✅ 정리 요약
| 항목 | 요약 | 
|---|---|
| BenchmarkDotNet | 가장 정확한 .NET 벤치마킹 도구 | 
| Stopwatch | 빠르게 비교할 때만 사용 | 
| MemoryDiagnoser | GC 할당량까지 확인 가능 | 
| 실무 적용 | 반복문, 문자열, 알고리즘 등 성능 튜닝 | 
📢 다음 챕터 예고 🎓
| 다음 챕터 | 주제 | 
|---|---|
| Chapter 3.6 | .NET 메모리 관리 이해 – GC 동작 원리 | 
728x90
    
    
  'C#' 카테고리의 다른 글
| C# 기초부터 고급까지 Chapter 3.7. 커스텀 Attributes, AOP 기법 적용 (1) | 2025.05.11 | 
|---|---|
| C# 기초부터 고급까지 Chapter 3.6. .NET 메모리 관리 이해 – GC 동작 원리 (2) | 2025.05.10 | 
| C# 기초부터 고급까지 Chapter 3.4. 고급 LINQ 커스터마이징 & 쿼리 최적화 (2) | 2025.05.06 | 
| C# 기초부터 고급까지 Chapter 3.3. Expression Tree로 컴파일 타임 코드 생성 (17) | 2025.05.05 | 
| C# 기초부터 고급까지 Chapter 3.2. Reflection & Dynamic Type – 런타임 메타프로그래밍 (0) | 2025.05.05 |