eej*_*i42 5 c# vb.net memory memory-management
我有一个应用程序,我正在尝试创建一个非常大的字节"立方体".一个3维数组(~1000x1000x500)保存了我感兴趣的所有值 - 但是我遇到了内存问题.虽然这是预期的,但我所获得的各种OOM消息的行为却令人困惑.第一:
Foo[,,] foo1 = new Foo[1000, 1000, 500];
因OOM错误而失败,但这不会:
Foo[,,] foo1 = new Foo[250, 1000, 500];
Foo[,,] foo2 = new Foo[250, 1000, 500];
Foo[,,] foo3 = new Foo[250, 1000, 500];
Foo[,,] foo4 = new Foo[250, 1000, 500];
这两组代码不应该消耗基本相同的内存量吗?
此外,我最初在消耗〜1.5GB时收到错误消息,但我认为通过将其切换到64位应用程序会让我在失败之前使用更多内存.
我是否遇到了堆栈空间限制?如果是这样,我怎样才能完全在堆上实例化这个结构,而不必在堆栈上存在(作为单个实体)?
在此先感谢 - 我期待任何人都可以对这种行为进行抨击.
编辑
我正在思考我的答案的功能更齐全的实现,我想我会追加。我不确定并行化是否有帮助,也许这取决于initializer.
using System;
using System.Linq;
public static T[][][] NewJagged<T>(
int h,
int w,
ing d,
Func<int, int, int, T> initializer = null,
bool parallelize = true)
{
if (h < 1)
{
throw new ArgumentOutOfRangeException("h", h, "Dimension less than 1.")
}
if (w < 1)
{
throw new ArgumentOutOfRangeException("w", w, "Dimension less than 1.")
}
if (d < 1)
{
throw new ArgumentOutOfRangeException("d", d, "Dimension less than 1.")
}
if (initializer == null)
{
initializer = (i, j, k) => default(T);
}
if (parallelize)
{
return NewJaggedParalellImpl(h, w, d, initializer);
}
return NewJaggedImpl(h, w, d, initializer);
}
private static T[][][] NewJaggedImpl<T>(
int h,
int w,
int d,
Func<int, int, int, T> initializer)
{
var result = new T[h][][];
for (var i = 0; i < h; i++)
{
result[i] = new T[w][];
for (var j = 0; j < w; j++)
{
result[i][j] = new T[d];
for (var k = 0; k < d; k++)
{
result[i][j][k] = initializer(i, j, k);
}
}
}
return result;
}
private static T[][][] NewJaggedParalellImpl<T>(
int h,
int w,
int d,
Func<int, int, int, T> initializer)
{
var result = new T[h][][];
ParallelEnumerable.Range(0, h).ForAll(i =>
{
result[i] = new T[w][];
ParallelEnumerable.Range(0, w).ForAll(j =>
{
result[i][j] = new T[d];
ParallelEnumerable.Range(0, d).ForAll(k =>
{
result[i][j][k] = initializer(i, j, k);
});
});
});
return result;
}
Run Code Online (Sandbox Code Playgroud)
这使得该函数完全通用,但仍然保留简单的语法,
var foo1 = NewJagged<Foo>(1000, 1000, 500);
Run Code Online (Sandbox Code Playgroud)
然而,您可以在初始化时花哨并并行填充,
var foo2 = NewJagged<Foo>(
1000,
1000,
5000,
(i, j, k) =>
{
var pos = (i * 1000 * 500) + (j * 500) + k;
return ((pos % 2) == 0) ? new Foo() : null;
});
Run Code Online (Sandbox Code Playgroud)
在这种情况下,填充棋盘效应(我认为。);
这最初似乎无法回答您的问题......
如果你有一个函数,像这样
public static T[][][] ThreeDimmer<T>(int h, int w, int d) where T : new()
{
var result = new T[h][][];
for (var i = 0; i < h; i++)
{
result[i] = new T[w][];
for (var j = 0; j < w; j++)
{
result[i][j] = new T[d];
for (var k = 0; k < d; k++)
{
result[i][j][k] = new T();
}
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后,您将封装引用类型的 3 维锯齿状数组的初始化。这将允许你做,
Foo[][][] foo1 = ThreeDimmer<Foo>(1000, 1000, 500);
Run Code Online (Sandbox Code Playgroud)
这将避免多维数组的内存碎片问题。它还可以避免其他陷阱和限制,为您提供更快、更灵活的锯齿状数组。