Я ударил OutOfMemoryException с помощью List <string> - это лимит, или я что-то упускаю?
Учитывая возможность переписать, я бы, но в любом случае, код в том виде, в каком он есть:
List<string> foobar;
Затем добавим связку строк в foobar.
В count = 16777216 мы попали в пределы памяти.
Я понимаю, что каждая строка будет другого размера. Действительно, глядя на данные (не мои данные), большинство из них - 2 или 3 символа.
Каков максимальный предел данных в список в С#?, указывает, что максимальный предел:
Максимальное количество элементов, которые могут быть сохранены в текущем реализация List - теоретически Int32.MaxValue - просто более 2 миллиардов.
Однако:
В текущей реализации Microsoft CLR есть 2 ГБ максимальный размер объекта. (Возможно, что другие реализации, например Mono, не имеют этого ограничения.)
В моем примере у меня есть, что, 16 миллионов результатов * несколько байтов? Диспетчер задач показывает, что используется гигабайт, но у меня есть 8 гигабайт оперативной памяти.
16777216 (2 ^ 24) кажется довольно специфическим значением - подозрительно, как предел, но я не могу найти какую-либо документацию в любом месте) назад или b) найти способ вокруг него?
Любая помощь будет оценена.
Некоторые коды:
List<string> returnList = new List<string>();
SqlDataReader dr; // executes a read on a database, have removed that part as that bit works fine
if (dr.HasRows)
{
while (dr.Read())
{
returnList.Add(dr.GetString(0).Trim());
}
}
Что упрощенная форма, теперь у меня есть попытка try/catch для исключения OOM, но это фактический код, который дает мне печаль.
Ответы
Ответ 1
Если вы пытаетесь использовать очень большие списки в 64-битных средах, вам нужно включить большие объекты в конфигурацию приложения.
http://msdn.microsoft.com/en-us/library/hh285054.aspx
OOM, вероятно, связано с тем, как списки/массивы распределяют память, и я считаю, что каждый раз, когда их граница достигнута, они пытаются удвоить размер. Список не может удваиваться от 2 ^ 24. Теоретически вы можете максимизировать свой размер списка, предварительно указав размер. (I.e. 2GB)
Ответ 2
Я опубликовал то, что я здесь сделал, стоит того, чтобы уйти.
Снова шаги:
- На каждой итерационной части запроса данных с использованием хранимой процедуры proc
- Перенесите их
-
Переместитесь к следующей части
List<string> returnList;
int index = 0;
SqlCommand cmd = new SqlCommand("ExampleStoredProc", conn);
cmd.CommandType = CommandType.StoredProcedure;
while (true)
{
cmd.Parameters.Add(
new SqlParameter("@index", index));
SqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
returnList = new List<string>();
returnList.Add(dr.GetString(0).Trim());
//transfer data here
}
else
{
break;
}
index++;
}
а хранимая процедура должна выглядеть примерно так:
CREATE PROCEDURE ExampleStoredProc
@index INT
AS
BEGIN
SELECT *
FROM veryBigTable
WHERE Id >= (@index *1000) AND Id < ((@index + 1) * 1000)
END
GO
Я определенно буду работать независимо от того, сколько записей у вас есть, просто чем больше данных у вас есть, тем больше времени потребуется.
Ответ 3
Если он получает даже меньше 2 ^ 24, когда вы вручную устанавливаете правильный размер списка, то это, вероятно, на правильном пути. Вместо того, чтобы доходить до 16 миллионов, а затем попытаться удвоить размер списка, это приведет к тому, что список будет действительно большим и начнется раньше.
Это объясняет, почему вы получили круглый номер - он достиг 2 ^ 24, а затем попытался увеличить размер, из-за чего он использовал слишком много памяти.
Мне кажется, что это какой-то "естественный" размер объекта, а не один в реализации списка.