Как заставить iis использовать больше памяти?
От: Jack128  
Дата: 22.09.10 12:22
Оценка:
Добрый день.

При чтении из базы данных блоба размером ~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);
            }
        }
Re: Как заставить iis использовать больше памяти?
От: Aen Sidhe Россия Просто блог
Дата: 22.09.10 12:53
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Добрый день.


J>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно.

J>С другой стороны в вижуал студио, при использовании иёйного http-сервера — все работает нормально работает.
J>Как жить то??

OutOfMemory != "мало памяти"
С уважением, Анатолий Попов.
ICQ: 995-908
Re: Как заставить iis использовать больше памяти?
От: Kuljok  
Дата: 22.09.10 12:55
Оценка:
Здравствуйте, 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 использовать больше памяти?
От: Aen Sidhe Россия Просто блог
Дата: 22.09.10 12:59
Оценка:
Здравствуйте, Kuljok, Вы писали:

K>Привет

K>даже на IIS 6 (ASP.NET 1.1) выделялось по умолчанию 2GB для процесса. Не думаю, что это происходит из-за чтения одного поля размером около 70MB.
K>Скорее всего просто где-то память не освобождается..., ну или еще по каким-то причинам система не может выделить больше памяти.

У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".
С уважением, Анатолий Попов.
ICQ: 995-908
Re[3]: Как заставить iis использовать больше памяти?
От: Jack128  
Дата: 22.09.10 13:12
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>Здравствуйте, Kuljok, Вы писали:


K>>Привет

K>>даже на IIS 6 (ASP.NET 1.1) выделялось по умолчанию 2GB для процесса. Не думаю, что это происходит из-за чтения одного поля размером около 70MB.
K>>Скорее всего просто где-то память не освобождается..., ну или еще по каким-то причинам система не может выделить больше памяти.

AS>У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".


Кстати, а вот как вобще возможна фрагментация памяти, если у нас gc по идее должен отслеживать нехватку памяти и дефрагментировать её?
Re[4]: Как заставить iis использовать больше памяти?
От: Aen Sidhe Россия Просто блог
Дата: 22.09.10 13:16
Оценка:
Здравствуйте, 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 использовать больше памяти?
От: Jack128  
Дата: 22.09.10 13:20
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>>>У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".


J>>Кстати, а вот как вобще возможна фрагментация памяти, если у нас gc по идее должен отслеживать нехватку памяти и дефрагментировать её?


AS>Элементарно. Ваш процесс не единственный в системе.


Ну и что? У нас же 70гигов свободной памяти?? Чем какой то левый процесс может нам помешать?
Re[6]: Как заставить iis использовать больше памяти?
От: Kuljok  
Дата: 22.09.10 13:25
Оценка: 12 (1)
Здравствуйте, Jack128, Вы писали:

J>Здравствуйте, Aen Sidhe, Вы писали:


AS>>>>У вас может быть свободно 70 гигов и при просьбе 70мегабайт вылететь это исключение. Называется "фрагментация RAM".


J>>>Кстати, а вот как вобще возможна фрагментация памяти, если у нас gc по идее должен отслеживать нехватку памяти и дефрагментировать её?


AS>>Элементарно. Ваш процесс не единственный в системе.


J>Ну и что? У нас же 70гигов свободной памяти?? Чем какой то левый процесс может нам помешать?


Вот статья есть неплохая по этому поводу.
Re: Как заставить iis использовать больше памяти?
От: Gollum Россия  
Дата: 23.09.10 09:06
Оценка:
Здравствуйте, Jack128, Вы писали:

J>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно.


Но это не причина эту память так переводить Ваш код можно безболезненно поменять, чтобы он не загружал весь файл в память, а грузил часть данных в небольшой буфер, который в свою очередь будет направляться в output stream.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Eugene Agafonov on the .NET

Re[7]: Как заставить iis использовать больше памяти?
От: Jack128  
Дата: 23.09.10 10:46
Оценка:
Здравствуйте, Kuljok, Вы писали:

K>Вот статья есть неплохая по этому поводу.


О, походу мой случай. У мя как раз косяк был в программе, очень часто необоснованно эти многомегобайтовые блобы грузились. Сенкс.
Re[2]: Как заставить iis использовать больше памяти?
От: Jack128  
Дата: 23.09.10 10:47
Оценка:
Здравствуйте, Gollum, Вы писали:

G>Здравствуйте, Jack128, Вы писали:


J>>При чтении из базы данных блоба размером ~70 МБ возникает ошибка OutOfMemory . Памяти на сервере более чем достаточно.


G>Но это не причина эту память так переводить Ваш код можно безболезненно поменять, чтобы он не загружал весь файл в память, а грузил часть данных в небольшой буфер, который в свою очередь будет направляться в output stream.


Ну вообще — нужно наследника Stream писать, который будет над DataReader'ом сидеть.
Re[3]: Как заставить iis использовать больше памяти?
От: Jack128  
Дата: 23.09.10 10:51
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Ну вообще — нужно наследника Stream писать, который будет над DataReader'ом сидеть.


Хотя гоню. Конект то закрывается по выходу из моего метода Download. А стрим будет читатся дальше по коду, где то в недрах MVC.

Так что либо нужно полностью данные из datareader'a в память выберать, либо сохранять их во временный файл и Filestream наружу отдавать...
Re[4]: Как заставить iis использовать больше памяти?
От: Gollum Россия  
Дата: 23.09.10 11:01
Оценка:
Здравствуйте, Jack128, Вы писали:

J>Так что либо нужно полностью данные из datareader'a в память выберать, либо сохранять их во временный файл и Filestream наружу отдавать...


Нет, нужно складывать в буфер порциями через reader.GetBytes(), а буфер выплевывать в Response.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Eugene Agafonov on the .NET

Re[4]: Как заставить iis использовать больше памяти?
От: Gollum Россия  
Дата: 23.09.10 14:58
Оценка: 6 (1)
Здравствуйте, 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();
        }
    }
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Eugene Agafonov on the .NET

Re[5]: Как заставить iis использовать больше памяти?
От: Jack128  
Дата: 24.09.10 09:02
Оценка:
Здравствуйте, Gollum, Вы писали:

Угу, суть понятна. Сенкс.
Re: Как заставить iis использовать больше памяти?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.09.10 07:53
Оценка:
Здравствуйте, 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.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.