При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно.
С другой стороны в вижуал студио, при использовании иёйного http-сервера — все работает нормально работает.
Как жить то??
Код:
public FileResult Download(int id)
{
using (var conn = new FbConnection(new FbConnectionStringBuilder
{
Database = @"localhost:c:\GrandUpdate\App_Data\UPDATES.FDB",
UserID = "SYSDBA",
Password = "masterkey"
}.ToString()))
{
conn.Open();
var command = conn.CreateCommand();
command.CommandText = @"select filename, data from gsdbases where id = {0}".Fmt(id);
var reader = command.ExecuteReader();
reader.Read();
var filename = (string)reader["filename"];
var dataCount = reader.GetBytes(1, 0, null, 0, int.MaxValue);
var buffer = new byte[dataCount];
reader.GetBytes(1, 0, buffer, 0, buffer.Length);
return File(buffer, "application/grandsmeta", filename);
}
}
Здравствуйте, Jack128, Вы писали:
J>Добрый день.
J>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно. J>С другой стороны в вижуал студио, при использовании иёйного http-сервера — все работает нормально работает. J>Как жить то??
Здравствуйте, Jack128, Вы писали:
J>Добрый день.
J>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно. J>С другой стороны в вижуал студио, при использовании иёйного http-сервера — все работает нормально работает. J>Как жить то??
J>Код: J>
J> public FileResult Download(int id)
J> {
J> using (var conn = new FbConnection(new FbConnectionStringBuilder
J> {
J> Database = @"localhost:c:\GrandUpdate\App_Data\UPDATES.FDB",
J> UserID = "SYSDBA",
J> Password = "masterkey"
J> }.ToString()))
J> {
J> conn.Open();
J> var command = conn.CreateCommand();
J> command.CommandText = @"select filename, data from gsdbases where id = {0}".Fmt(id);
J> var reader = command.ExecuteReader();
J> reader.Read();
J> var filename = (string)reader["filename"];
J> var dataCount = reader.GetBytes(1, 0, null, 0, int.MaxValue);
J> var buffer = new byte[dataCount];
J> reader.GetBytes(1, 0, buffer, 0, buffer.Length);
J> return File(buffer, "application/grandsmeta", filename);
J> }
J> }
J>
Привет
даже на IIS 6 (ASP.NET 1.1) выделялось по умолчанию 2GB для процесса. Не думаю, что это происходит из-за чтения одного поля размером около 70MB.
Скорее всего просто где-то память не освобождается..., ну или еще по каким-то причинам система не может выделить больше памяти.
Можно провеирть запустив perfmon.
Re[2]: Как заставить iis использовать больше памяти?
Здравствуйте, Kuljok, Вы писали:
K>Привет K>даже на IIS 6 (ASP.NET 1.1) выделялось по умолчанию 2GB для процесса. Не думаю, что это происходит из-за чтения одного поля размером около 70MB. K>Скорее всего просто где-то память не освобождается..., ну или еще по каким-то причинам система не может выделить больше памяти.
У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".
С уважением, Анатолий Попов.
ICQ: 995-908
Re[3]: Как заставить iis использовать больше памяти?
Здравствуйте, Aen Sidhe, Вы писали:
AS>Здравствуйте, Kuljok, Вы писали:
K>>Привет K>>даже на IIS 6 (ASP.NET 1.1) выделялось по умолчанию 2GB для процесса. Не думаю, что это происходит из-за чтения одного поля размером около 70MB. K>>Скорее всего просто где-то память не освобождается..., ну или еще по каким-то причинам система не может выделить больше памяти.
AS>У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".
Кстати, а вот как вобще возможна фрагментация памяти, если у нас gc по идее должен отслеживать нехватку памяти и дефрагментировать её?
Re[4]: Как заставить iis использовать больше памяти?
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, Aen Sidhe, Вы писали:
AS>>Здравствуйте, Kuljok, Вы писали:
K>>>Привет K>>>даже на IIS 6 (ASP.NET 1.1) выделялось по умолчанию 2GB для процесса. Не думаю, что это происходит из-за чтения одного поля размером около 70MB. K>>>Скорее всего просто где-то память не освобождается..., ну или еще по каким-то причинам система не может выделить больше памяти.
AS>>У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".
J>Кстати, а вот как вобще возможна фрагментация памяти, если у нас gc по идее должен отслеживать нехватку памяти и дефрагментировать её?
Элементарно. Ваш процесс не единственный в системе.
С уважением, Анатолий Попов.
ICQ: 995-908
Re[5]: Как заставить iis использовать больше памяти?
Здравствуйте, Aen Sidhe, Вы писали:
AS>>>У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".
J>>Кстати, а вот как вобще возможна фрагментация памяти, если у нас gc по идее должен отслеживать нехватку памяти и дефрагментировать её?
AS>Элементарно. Ваш процесс не единственный в системе.
Ну и что? У нас же 70гигов свободной памяти?? Чем какой то левый процесс может нам помешать?
Re[6]: Как заставить iis использовать больше памяти?
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, Aen Sidhe, Вы писали:
AS>>>>У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".
J>>>Кстати, а вот как вобще возможна фрагментация памяти, если у нас gc по идее должен отслеживать нехватку памяти и дефрагментировать её?
AS>>Элементарно. Ваш процесс не единственный в системе.
J>Ну и что? У нас же 70гигов свободной памяти?? Чем какой то левый процесс может нам помешать?
Здравствуйте, Jack128, Вы писали:
J>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно.
Но это не причина эту память так переводить Ваш код можно безболезненно поменять, чтобы он не загружал весь файл в память, а грузил часть данных в небольшой буфер, который в свою очередь будет направляться в output stream.
Здравствуйте, Gollum, Вы писали:
G>Здравствуйте, Jack128, Вы писали:
J>>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно.
G>Но это не причина эту память так переводить Ваш код можно безболезненно поменять, чтобы он не загружал весь файл в память, а грузил часть данных в небольшой буфер, который в свою очередь будет направляться в output stream.
Ну вообще — нужно наследника Stream писать, который будет над DataReader'ом сидеть.
Re[3]: Как заставить iis использовать больше памяти?
Здравствуйте, Jack128, Вы писали:
J>Так что либо нужно полностью данные из datareader'a в память выберать, либо сохранять их во временный файл и Filestream наружу отдавать...
Нет, нужно складывать в буфер порциями через reader.GetBytes(), а буфер выплевывать в Response.
Здравствуйте, Jack128, Вы писали:
J>Так что либо нужно полностью данные из datareader'a в память выберать, либо сохранять их во временный файл и Filestream наружу отдавать...
Вот примерный код (писал в редакторе януса, так что осторожнее)
Это контроллер экшн
public FirebirdFileBlobReaderActionResult Download(int id)
{
string connectionString = new FbConnectionStringBuilder
{
Database = @"localhost:c:\GrandUpdate\App_Data\UPDATES.FDB",
UserID = "SYSDBA",
Password = "masterkey"
}.ToString();
// можно если хочется дописать экстенжн метод к контроллеру и возвращать его вызов типа
// return FirebirdFileBlob(connectionString, id);return new FirebirdFileBlobReaderActionResult(connectionString, id);
}
это actionresult
public class FirebirdFileBlobReaderActionResult : ActionResult
{
private readonly string _connectionString;
private readonly int _id;
public FirebirdFileBlobReaderActionResult(string connectonString, int id)
{
_connectionString = connectonString;
_id = id;
}
public override void ExecuteResult(ControllerContext context)
{
using (var conn = new FbConnection(_connectionString))
{
conn.Open();
var command = conn.CreateCommand();
//а что, тут нормальные ADO.NET параметры не поддерживаются?!
command.CommandText = @"select filename, data from gsdbases where id = {0}".Fmt(_id);
var reader = command.ExecuteReader();
const int bufferSize = 1000;
var buffer = new byte[bufferSize];
int bytesRead;
int startIndex = 0;
while (reader.Read())
{
context.HttpContext.Response.ContentType = "application/grandsmeta";
// не помню как правильно, проверить в rfc
context.HttpContext.Response.AddHeader("Content-Disposition",
string.Format("attachment, filename={0}", reader["filename"]));
bytesRead = reader.GetBytes(1, startIndex, buffer, 0, bufferSize);
Stream outputStream = context.HttpContext.Response.OutputStream;
while (bytesRead == bufferSize)
{
outputStream.Write(buffer, 0, bufferSize);
outputStream.Flush();
// Reposition start index to end of last buffer and fill buffer.
startIndex += bufferSize;
bytesRead = reader.GetBytes(1, startIndex, buffer, 0, bufferSize);
}
if (0 != bytesRead) outputStream.Write(buffer, 0, bytesRead);
outputStream.Flush();
}
}
}
Здравствуйте, Jack128, Вы писали:
J>Добрый день.
J>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory. Памяти на сервере более чем достаточно. J>С другой стороны в вижуал студио, при использовании иёйного http-сервера — все работает нормально работает. J>Как жить то??
J>Код: J>
J> public FileResult Download(int id)
J> {
J> using (var conn = new FbConnection(new FbConnectionStringBuilder
J> {
J> Database = @"localhost:c:\GrandUpdate\App_Data\UPDATES.FDB",
J> UserID = "SYSDBA",
J> Password = "masterkey"
J> }.ToString()))
J> {
J> conn.Open();
J> var command = conn.CreateCommand();
J> command.CommandText = @"select filename, data from gsdbases where id = {0}".Fmt(id);
J> var reader = command.ExecuteReader();
J> reader.Read();
J> var filename = (string)reader["filename"];
J> var dataCount = reader.GetBytes(1, 0, null, 0, int.MaxValue);
J> var buffer = new byte[dataCount];
J> reader.GetBytes(1, 0, buffer, 0, buffer.Length);
J> return File(buffer, "application/grandsmeta", filename);
J> }
J> }
J>
Во первых код два раза читает по 70 МБ. Один раз ридер из базы, второй раз при копировании в буфер.
Надо указывать как минимум CommandBehavior.SequentialAccess (хотя не знаю насколько это верно для FB, но рекомедуют так делать всегда).
Причина OOM может заключаться в том что в одном AppPool работает несколько сайтов, а виртуальной памяти в х86 довольно мало получает, вот она и заканчивается. Сделайте отдельный apppool, для него будет запускаться отдельный w3wp процесс, или переведите все в x64.