91 lines
2.8 KiB
Markdown
91 lines
2.8 KiB
Markdown
# 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效果
|
||
- 如果仍有问题,考虑为最常用的值添加快速路径 |