如图, 频繁申请新的数组,导致偶尔报错OutOfMemoryException(重点:偶尔),很奇怪的问题,明明内存够,却报错OutOfMemoryException。
分析:数组地址是连续的,我这是图片数据,大小可能有的大,导致频繁申请新的连续地址不够,以前使用过的数组GC又没有来得及回收(大概140ms申请一次连续地址),所以报此错。
解决方案:1.直接加内存(开玩笑)
2.程序启动申请一个固定大小的内存地址,每次去覆盖此数组的值,而不去创建新的地址。
自己封装了一个类使用如下:
public class LargeArray
{
private readonly int _capacity;
private readonly int _arraySize;
private readonly byte[][] _array;
private volatile int _currentIndex = 0;
public LargeArray(int capacity, int arraySize)
{
if (capacity <= 0 || arraySize <= 0)
throw new Exception("大小必须大于0");
this._capacity = capacity;
this._arraySize = arraySize;
this._array = new byte[capacity][];
for (int i = 0; i < capacity; i++)
{
this._array[i] = new byte[arraySize];
}
}
public int ArraySize
{
get
{
return this._arraySize;
}
}
public int Capacity
{
get
{
return this._capacity;
}
}
public int CurrentIndex
{
get
{
return this._currentIndex;
}
private set
{
if (value == this.Capacity)
value = 0;
this._currentIndex = value;
}
}
public IntPtr Pointer
{
set
{
Marshal.Copy(value, ArrayData, 0, this._arraySize);
}
}
public byte[] ArrayData
{
get
{
return this._array[CurrentIndex];
}
set
{
this._array[CurrentIndex++] = value;
}
}
}
这里的capacity是创建几个大小相同的数组,arraySize是每个数组的大小。
使用:
_largeArray是全局变量,最终获取数组_largeArray.ArrayData就可(注意:在使用的时候需要及时使用,因为会被后面的覆盖,如果来不及使用,可以把capacity设置大一点,最好合理的大小,太大会浪费资源) 。本例子中_largeArray.Pointer = e.Pointer将值赋值到数组,然后Data = _largeArray.ArrayData立马加入到队列等待使用,此时绘图线程可能来不及使用,但是我开启了3个,所以中间有一定的缓冲,设置capacity越大,缓冲时间越长,开销的内存资源就越多,如果来不及使用就会被覆盖,图像要么出现跳要么就出现乱。
ps:我这里创建图像线程只负责生产数组数据,不绘图,绘图在另外的线程,可能会慢点,所以我这里设置3个数组作为绘图线程的缓冲。
对比之前的图像,现在的内存反而降低了不少。。。