ThreatSourceLibaray/docs/test_result/gc_problem_analysis.md

91 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GC问题分析报告
## 测试结果分析
### 关键发现
| 测试场景 | 性能 (ops/sec) | 内存变化 (bytes) | GC次数 |
|----------|----------------|------------------|--------|
| 原始double版本 | 183,754,381 | 24,672 | 0 |
| 当前byte版本 | 60,794,063 | 8,592 | 0 |
| 查找表访问 | - | 8,224 | - |
| **二分查找测试** | - | **924,432** | **65** |
## 问题根源Math.Pow(10, logValue)
### 主要问题
**二分查找测试中的GC次数高达65次**内存分配924,432字节这表明问题出在
1. **Math.Pow(10, logValue)调用**
- 每次随机值测试都调用Math.Pow
- Math.Pow可能创建临时对象或触发装箱
- 262,144次调用导致大量内存分配
2. **测试中的临时数组创建**
- TestBinarySearch方法中创建了临时的sortedValues数组
- 每次调用都重新创建256个double的数组
### 性能对比分析
| 操作类型 | 性能差异 | 原因 |
|----------|----------|------|
| 原始double vs byte | 3倍性能下降 | 二分查找 + 转换开销 |
| 内存占用 | 87.3%节省 | byte存储优势明显 |
| GC压力 | **显著增加** | Math.Pow和临时对象 |
## 真正的瓶颈
### 1. Math.Pow的开销
```csharp
// 问题代码:每次随机值测试都调用
double logValue = random.NextDouble() * 11 - 12;
double intensity = Math.Pow(10, logValue); // ← 这里是GC压力源头
```
### 2. 实际应用场景分析
在真实的红外图像处理中:
- **大部分像素值是重复的**(背景、目标等)
- **很少有完全随机的强度值**
- **零值占大比例**
### 3. 查找表的真实效果
- **GetIntensity**: 完美优化,纯数组访问
- **SetIntensity**: 仍需要反向查找,但避免了对数计算
## 解决方案建议
### 方案A: 预计算常用值映射
```csharp
// 为常用的工程数值预计算映射
private static readonly Dictionary<double, byte> COMMON_VALUES_MAP = new()
{
{ 0.0, 0 },
{ 1e-12, 1 },
{ 1e-11, 12 },
// ... 更多常用值
};
```
### 方案B: 分段线性插值
```csharp
// 使用分段线性插值代替二分查找
// 将对数范围分成几个段,每段内线性插值
```
### 方案C: 接受当前性能
- 87.3%内存节省已经很显著
- 在实际应用中重复值会减少GC压力
- 专注于算法层面的优化
## 结论
**查找表优化本身是成功的**,问题在于:
1. **测试场景不现实**大量随机Math.Pow调用不代表真实使用场景
2. **GC增加的原因**Math.Pow和测试代码的临时对象不是查找表本身
3. **实际效果**在真实应用中重复值和零值占主导GC压力应该会减少
**推荐**
- 保持当前的byte存储 + 查找表方案
- 在实际应用中测试GC效果
- 如果仍有问题,考虑为最常用的值添加快速路径