Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > нехватка оперативной памяти ?


Автор: Remiznik 30.7.2009, 14:37
Нужно загрузить очень большой фале в ОП но её может не хватить как сделать чтоб программа не падала от нехватки ОП ?

У меня есть две идеи но как их реализовать не знаю !
1. Начать закружать ОП и если она кончиться то перехватить это исключение и обработать  его. 
2. Каким-то обзором определить количество свободной ОП до начала загрузки файла и уже там думать что с этим делать.

По 1 не знаю какое исключение генерируется и как его отловить. 
По 2 не знаю как определить кол-во свободной ОП.

Посоветуйте что делать, или может есть ешо какие идеи для предотвращения паления программы ! 

Автор: Sartorius 30.7.2009, 14:39
А вы про виртуальную память слышали? До вас уже обо всем позаботились...

ЗЫ Что то мне подсказывает, что вашу задачу можно решить без загрузки в память всего файла.

Автор: azesmcar 30.7.2009, 14:45
Remiznik

Используй функцию http://linux.die.net/man/2/mmap.

Автор: Cheloveck 30.7.2009, 15:52
Цитата(Sartorius @  30.7.2009,  15:39 Найти цитируемый пост)
ЗЫ Что то мне подсказывает, что вашу задачу можно решить без загрузки в память всего файла.


Sartorius мне подсказывает, что то, что мне что-то подсказывает, что вашу задачу можно решить без загрузки всего файла в ОП, правильно. Я, вот сейчас работаю с файлами 100+ Mb и использую потоки.

Автор: Remiznik 1.8.2009, 15:07
azesmcar, спасибо за ссылку но както пока не разобрался как использовать эту функцию ... примера нет а по описанию мне както не вникнуть что она делает .

Cheloveck а можно поподробнее по потоки , как ты их используешь чтоб не загружать весь в фаел в ОП ?

Автор: azesmcar 1.8.2009, 15:42
Цитата(Remiznik @  1.8.2009,  15:07 Найти цитируемый пост)
azesmcar, спасибо за ссылку но както пока не разобрался как использовать эту функцию ... примера нет а по описанию мне както не вникнуть что она делает .

Что, примеров не нашел?
http://www.cs.purdue.edu/homes/fahmy/cs503/mmap.txt
http://www.linuxquestions.org/questions/programming-9/mmap-tutorial-cc-511265/
http://www.devshed.com/c/a/BrainDump/Using-mmap-for-Advanced-File-IO/
http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/apis/mmap.htm
http://www.ecst.csuchico.edu/~beej/guide/ipc/mmap.html

Добавлено через 57 секунд
Цитата(Remiznik @  1.8.2009,  15:07 Найти цитируемый пост)
что она делает

Написано же
Цитата

The mmap() function asks to map length bytes starting at offset offset from the file (or other object) specified by the file descriptor fd into memory

http://www.translate.ru

Автор: Remiznik 1.8.2009, 15:52
то есть в функцию передаём файл и она проверяет поместится он в ОП или нет ?


Автор: azesmcar 1.8.2009, 17:18
Цитата(Remiznik @  1.8.2009,  15:52 Найти цитируемый пост)
то есть в функцию передаём файл и она проверяет поместится он в ОП или нет ?

нет, проецирует файл в память.

Автор: Cheloveck 2.8.2009, 13:23
Цитата(Remiznik @  1.8.2009,  16:07 Найти цитируемый пост)

Cheloveck а можно поподробнее по потоки , как ты их используешь чтоб не загружать весь в фаел в ОП ? 

Код


// Копирует всё содержимое input в output.
void copy_stream( std::ifstream & input, std::ofstream & output )
{
    if( !input.is_open() || input.eof() || !output.is_open() )
        return;

    std::string str;
    while( !input.eof() && std::getline( input, str ) )
    {
        output << str << std::endl;
    }
}

Вот кусок из одной из моих прог.

Автор: andrew_121 2.8.2009, 13:58
Cheloveck, Что-то я не вижу чтоб было указанно что данные только текстовые.

Добавлено через 6 минут и 26 секунд
Remiznik, Так задача собственно какая? Скопировать файл?
Если да, то тут:
http://forum.vingrad.ru/forum/topic-267913.html

Автор: LisAnd 3.8.2009, 12:11
Отображаемая память рулитsmile

Автор: Remiznik 3.8.2009, 21:19
задача в том что есть файл там данные записаны особенным обзором и их не просто нужно загрузить в память а в вектор но прежде чем загрузить в вектор нужно выделить под него память а если файл слишком большой выдать предупреждении !

Код

 struct mystruct
{
    int param1;
    int param2;
}

vector<mystruct> Data;

int size;           // количество данных 
Data.resize(size);


и мне нужно знать хватит ли места в ОП для этого вектора.

Автор: vinick 3.8.2009, 22:05
Цитата(Remiznik @  3.8.2009,  21:19 Найти цитируемый пост)
и мне нужно знать хватит ли места в ОП для этого вектора. 

Можешь попробовать ловить std::bad_alloc из resize и SIGSEGV. resize вызывает констурторы для элементов, следовательно доступ к памяти будет, а значит либо исключение, либо сигнал выстрелят.

 Но лучше пересмотреть алгоритм. Что ты будешь делать если файл попадется такой, что со скрипом влезет в память, но ни на что другое памяти уже не останется? А что делать пользователю с твоим предупреждением? бежать в магазин за планкой памяти, за двумя или заказывать кластер на петабайт?

Автор: Remiznik 3.8.2009, 22:27
да я понимаю что все данные загружать в ОП это абсурд ... но если файл не помешается в ОП то я применю алгоритм и буду выборочно загружать .... но если файл помешается то надо загрузить !

Автор: andrew_121 3.8.2009, 22:27
Напиши свой объект вектор. В нем, вместо выделения памяти, используй проецирование файла в память.
Какие именно операции ты выполняешь с этим вектором?

Автор: Remiznik 3.8.2009, 22:35
просто я использую эти данные для дальнейшей обработки ....можно конечно напрямую данные брать из файла на диске но это при большом количестве обращений к файлу очень влияет на время работы.

Автор: andrew_121 3.8.2009, 22:50
Remiznik, Ты не понял.

Цитата(andrew_121 @  3.8.2009,  22:27 Найти цитируемый пост)
Какие именно операции ты выполняешь с этим вектором? 

Т.е. Какие методы вектора, содержащего данные из этого файла, тебе нужны?

Пример:
Код

struct mystruct {
    int param1;
    int param2;
};


template<typename T> class MyVector {
public:
    MyVector(const std::string& filename) {
        ...
        uint filesize = ...;
        int fd = open(filename, ...);
        
        _ptr = mmap(..., fd, ...); /* <<<<<<<<<<<<<<<<<<<<<<<< */
        
        _count = filesize / sizeof(T);
    }
    const T& operator[] (int idx) const {
        if ( idx <= _count ) {
            return *(const T*)_ptr+idx*sizeof(T);
        }
        return T(); /* что-то типа этого или исключение*/
    }
protected:
    uint _count;
    char* _ptr;
};

int main(int argc, const char **argv) {
    MyVector<mystruct> vec("./file.dat");
    return 0;
}


Вот. Реализуй необходимые тебе методы.

Добавлено @ 22:52
Я показал пример реализации вектора с перегруженным оператором индексирования.

Автор: Remiznik 3.8.2009, 23:00
да только функцию воврашения значения по индексу который мне нужен. Просто вектор использую в место массива мне так удобнее.

Автор: andrew_121 3.8.2009, 23:11
Remiznik, Ну вот тебе каркас вектора использующего проецирование файла в память. Допиши и используй на здоровье.

Добавлено через 9 минут и 41 секунду
Щас поэкспериментирую, любопытно smile 

Автор: andrew_121 4.8.2009, 01:00
В общем вот что получилось.
Код

#include <io.h>
#include <fcntl.h>

#include <string>
#include <cassert>
#include <iostream>
#include <fstream>
#include <exception>

#ifdef WIN32
#  include "glibc/mman.h"
#else
#  include <sys/mman.h>
#endif

class bad_index : public std::exception {
public:
    bad_index() throw() : std::exception() {}
    virtual ~bad_index() {}
};

class not_init : public std::exception {
public:
    not_init() throw() : std::exception() {}
    virtual ~not_init() {}
};

template<typename T> class MyVector {
public:
    MyVector(const std::string& fn):_fd(-1), _fs(0), _count(0), _fn(fn), _ptr(NULL) {}
    virtual ~MyVector() {}
    /*  */
    bool good() const { return _fd != -1; }
    int count() const {
        if ( _fd < 0 ) {
            throw not_init();
        }
        return _count;
    }
    /*  */
    bool init() {
        _fd = open(_fn.c_str(), _O_BINARY|_O_RDONLY);
        if ( _fd < 0 ) return false;
        
        lseek(_fd, 0L, SEEK_END);
        _fs = tell(_fd);
        lseek(_fd, 0L, SEEK_SET);
        
        _count = _fs/sizeof(T);
        
        _ptr = (char*)mmap(NULL, _fs, PROT_READ, MAP_PRIVATE, _fd, 0);
        return _ptr != NULL;
    }
    void free() {
        if ( _ptr ) {
            munmap(_ptr, _fs);
            _ptr = NULL;
        }
        if ( _fd > 0 ) {
            close(_fd);
            _fd = -1;
        }
    }
    const T& operator[] (int idx) const {
        if ( idx < 0 || idx > _count ) {
            throw bad_index();
        }
        return *(const T*)(_ptr+idx*sizeof(T));
    }
protected:
    int _fd;
    int _fs;
    int _count;
    std::string _fn;
    char* _ptr;
};

struct mystruct {
    int param1;
    int param2;
};

void create_file(const std::string& fn, int count) {
    std::ofstream file(fn.c_str(), std::ios::binary);
    if ( !file.good() ) return;
    
    mystruct data;
    while ( count-- ) {
        data.param1 = data.param2 = rand();
        
        file.write((const char*)&data, sizeof(data));
    }
    
    file.close();
}

int main(int argc, const char **argv) {

    const int count = 1024*1024*100;
    const std::string filename("data.dat");
    create_file(filename, count);

    MyVector<mystruct> vec(filename);
    mystruct data;
    
    assert(vec.init());
    
    try {
        int cnt = vec.count();
        assert(cnt == count);
        int idx = 0;
    
        while ( cnt-- ) {
            data = vec[idx++];
        }
    }
    catch ( const bad_index& e ) {
        std::cout << "bad_index" << std::endl;
    }
    catch ( const not_init& e ) {
        std::cout << "not_init" << std::endl;
    }
    catch ( ... ) {
        std::cout << "who?" << std::endl;
    }
    vec.free();
    
    return 0;
}

Странное поведение под виндавз. Съедает всю память, даже отбирает ее у запущенных программ/процессов. В Linux, все в порядке. Выделяет не больше чем свободной памяти есть. Процессы не обделяет.

Автор: MAKCim 5.8.2009, 19:43
Цитата(Remiznik @  3.8.2009,  22:35 Найти цитируемый пост)
можно конечно напрямую данные брать из файла на диске но это при большом количестве обращений к файлу очень влияет на время работы. 

1. fread/fwrite используют кэш
2. mmap работает так же как и fread за исключением того, что чтение происходит неявным образом
+readahead, который, к слову реализуется и через fread

Добавлено через 1 секунду
Цитата(Remiznik @  3.8.2009,  22:35 Найти цитируемый пост)
можно конечно напрямую данные брать из файла на диске но это при большом количестве обращений к файлу очень влияет на время работы. 

1. fread/fwrite используют кэш
2. mmap работает так же как и fread за исключением того, что чтение происходит неявным образом
+readahead, который, к слову реализуется и через fread


Автор: andrew_121 5.8.2009, 21:46
Цитата(MAKCim @  5.8.2009,  19:43 Найти цитируемый пост)
1. fread/fwrite используют кэш

Да.
Но если учесть что нужен произвольный доступ, не думаю что кэш будет работать при большом объеме файла.


Цитата(MAKCim @  5.8.2009,  19:43 Найти цитируемый пост)
readahead

Не знал что есть такое. smile  Спасибо!

Автор: MAKCim 6.8.2009, 20:39
Цитата(andrew_121 @  5.8.2009,  21:46 Найти цитируемый пост)
не думаю что кэш будет работать при большом объеме файла.

setvbuf

Автор: andrew_121 6.8.2009, 21:14
Цитата(MAKCim @  6.8.2009,  20:39 Найти цитируемый пост)
setvbuf 

Нужно экспериментировать.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)