Narzędzia użytkownika

Narzędzia witryny


wlasne_funkcje_obslugi_braku_pamieci

To jest stara wersja strony!


Własne funkcje obsługi braku pamięci

Marcin Kaczor U3ISI nr albumu: 192641

Problem: Podczas korzystania z dynamicznego przydzialu pamieci w jezyku C++ (za pomoca operatora new) jesli nie uda sie zarezerwowac bloku pamieci o odpowiednim rozmiarze, to zostanie rzucony wyjatek std::bad_alloc. Sprawdzanie czy po każdym wywolaniu new nie zostal rzucony wyjatek jest klopotliwe. Oczywiscie mozna uzywac wersji operatora new, ktora nie rzuca wyjatkiem new (std::nothrow) Typ, ale wtedy pomijamy obsługę błędów.

Opis: Bilbioteka standardowa udostepnia mozliwosc zdefiniowania wlasnej funkcji obslugi braku pamieci za pomoca funkcji z biblioteki standardowej set_new_handler(). Funkcja obslugi braku pamieci powinna uzyskac wiecej pamieci, rzucic wyjatek, przerwac program lub chociaz ustawic inna funkcje obslugi (lub odinstalowac obecna), bo program bedzie sie wykonywal w nieskonczonej petli.

Zastosowanie: Glownym zadaniem funkcji obslugi braku pamieci jest uzyskanie wiekszej ilosci pamieci (np. przez usuniecie nieuzywanych obiektow) tak aby aplikacja mogla dzialac dalej, czasami jest to niemozliwe, funkcja ta jest tez przydatna gdy nie chcemy przy kazdym tworzeniu nowego obiektu obslugiwac wyjatku bad_alloc, w ten sposob, gdy juz wystapi problem braku pamieci mozemy to obsluzyc w jednym miejscu i zamknac aplikacje w mniej brutalny sposob, mamy szanse na pozamykanie polaczen, plikow oraz poinformowanie uzytkownika o tym co sie stalo.

Przyklad: Nizej zostanie przedstawiony przyklad klasy reprezentujacej obiekty zajmujace duzo pamieci, obiekty beda rejestrowane w rejstrze przez ktory tez jest mozliwy do nich dostep, rejestr bedzie usuwac obiekty gdy bedzie potrzebna pamiec.

#include <new>               // zawiera funkcje set_new_handler
#include <iostream>          // obiekty cout, cerr, etc.
#include <cstdlib>           // exit() - awayjne wyjscie
#include <vector>            // wektor obietktow BigSize
 
//! wielkosc bufora powiekszajacego rozmiar BigSize
#define BS_SIZE 200000000
 
// deklaracja klasy Register potrzebna klasie BigSize
class Register;
 
//! Klasa BigSize
/*!
  Klasa BigSize reprezentuje duze obiekty w pamieci, np. warstwy w zaawansowanym
  programie do obrobki grafiki rastrowej lub zapamietywanie histori zmian w obrazie.
*/
class BigSize
{
  friend class Register;
 
private:
  //! Prywatny konstruktor, tylko obiekty klasy Register maja prawo tworzyc obiekty
  //! BigSize. Dla celow testowych informuje uzytkownika o stworzeniu obiektu
  BigSize()
  {
    std::cout << "Creating BigSize..." << std::endl;
  }
 
  //! Prywatny konstruktor kopiujacy, zabezpiecza przed kopiowaniem obiektow,
  //! dostep do obiektu jest mozliwy tylko przez klase register
  BigSize(const BigSize &) {};
 
  //! Prywatny destruktor, tylko obiekty klasy Register maja prawo niszczyc obiekty
  //! BigSize. Dla celow testowych informuje uzytkownika o usunieciu obiektu
  ~BigSize()
  {
    std::cout << "Deleting BigSize..." << std::endl;
  }
 
private:
  //! Tablica znakow, bufor, w przykladzie tylko sztucznie powieksza rozmiar klasy
  char buffer_[BS_SIZE];
};
 
//! Klasa Register
/*!
  Klasa Register tworzy, usuwa i przechowyje wskazania na obiekty BigSize,
  zaimplemneotwna jako Singleton, mozna przy implemntacji wykorzystac rowniez
  wzorzec fabryki
*/
class Register
{
private:
  //! Prywatny konstrukotr domyslny i kopiujacy
  Register() : counter_(0) {};
  Register(const Register &r);
 
public:
  //! Metoda pobierajaca referencje do obiektu
  static Register& getInstance()
  {
    static Register instance;
    return instance;
  }
 
  //! Tworzenie nowego obiektu klasy BigSize
  BigSize *getNewBigSize()
  {
    BigSize *bs = new BigSize();
    objects_.push_back(bs);
    counter_++;
    return bs;
  }
 
  //! zwolnienie nieuzywanych obiektow, w tym przykladzie wszystkie obiekty sa nieuzywane
  //! metoda zwaraca true zostala zwolniona jakakolwiek ilosc pamieci, w przeciwnym razie false
  bool deleteUnusedObjects()
  {
    bool retval = counter_ > 0 ? true : false;
 
    while (counter_--) {
      delete objects_.back();
      objects_.pop_back();
    }
    counter_ = 0;
    return retval;
  }
 
  //! Pobranie obiektu klasy BigSize o zadanym indeksie, niewykorzystywane w przykladzie
  BigSize *getBigSize(int index)
  {
    if (index > 0 && index < counter_)
      return objects_[index];
    else
      return NULL;
  }
 
private:
  int counter_; /**< licznik obiektow */
  std::vector<BigSize *> objects_; /**< wektor obiektow */
};
 
//! Funkcja obslugi braku pamieci, zamyka awaryjnie aplikacje
void KillApplication()
{
  // informacja dla uzytkownika, w zaleznosci od potrzeb moze byc zapisana do logu
  std::cerr << "Pamiec zostala wyczerpana, awaryjne zamykanie aplikacji." << std::endl;
  // awaryjne zamykanie aplikacji, zapisanie stanu, zamkniecie plikow, polaczen, etc.
  exit(1);
}
 
//! Funkcja obslugi braku pamieci, sprzata pamiec
void CleanUpMemory()
{
  // informacja dla uzytkownika, potrzebna raczej tylko dla aplikacji testowej
  std::cout << "Pamiec zostala wyczerpana, usuwanie niepotrzebnych obiektow." << std::endl;
  if (!Register::getInstance().deleteUnusedObjects()) { // nie udalo sie zwolnic pamieci
    std::set_new_handler(KillApplication); // ustawienie nowej funkcji obslugi braku pamieci
    return;
  }
  exit(1); // program moze kontynuowac dzialanie, bo zwolniono czesc nieuzywanej pamieci,
           // ale w tym przykladzie dzialalby w petli nieskonczonej, dlatego zostanie zamkniety
}
 
 
int main ()
{
  std::set_new_handler(CleanUpMemory); // ustawienie nowej funkcji obslugi braku pamieci
  for(;;) {
    Register::getInstance().getNewBigSize(); // zajmowanie pamieci :-)
  }
  return 0;
}
wlasne_funkcje_obslugi_braku_pamieci.1228339943.txt.gz · ostatnio zmienione: 2008/12/03 22:32 przez marcinkaczor