Hlavní navigace

GLib: Bleskové operace s pamětí

25. 4. 2000
Doba čtení: 4 minuty

Sdílet

V dnešním díle věnovaném knihovně GLib si povíme něco o možnostech urychlení operací alokace paměti.

S dynamickou alokací paměti je spojena určitá „režie“. Tím, že zavoláte například funkci g_malloc(), se musí provést mnoho operací, které samozřejmě zdržují a navíc interními záznamy ukrádají místo v paměti. Pokud za běh programu dynamicky alokujete relativně nízký počet proměnných, je časové zdržení zanedbatelné. Co když je však těchto proměnných tisíc? Nebo milión? Pak už myslím tyto „režie“ poznáte.

Autoři knihovny GLib naprogramovali mechanizmus, který alokuje najednou velký blok paměti, do kterého jsou pak umísťovány jednotlivé proměnné, které by se jinak alokovaly samostatně. Ušetří se tak strojový čas a trochu místa v paměti. Takovým úsekům paměti se anglicky říká Memory Chunks a položkám v nich umístěným atoms. Nebudu se pokoušet doslova přeložit tyto pojmy. Myslím, že bude srozumitelnější, budu-li je používat tak, jak je zavedli kolegové :-) na druhé straně Atlantiku.

Diagram struktury paměťového chunku

Obrázek 1 – Diagram struktury paměťového chunku

Jak to tedy všechno funguje? Nejdříve vytvoříte nový chunk – alokuje se tím jeden blok paměti stanovené délky. Do chunku pak můžete umisťovat jednotlivé proměnné, atomy. Je-li blok plný, vytvoří se automaticky nový, stejné velikosti. A tak to jde vesele dál, ale o něco rychleji než standardními prostředky, protože se paměť nealokuje po malých kousíčkách, ale rovnou ve velkých blocích.

Základem mechanizmu je struktura

struct GMemChunk; 

…reprezentující paměťový chunk. Přístup do ní by měl být realizován výhradně níže popsanými funkcemi.

Vytvoření nového GMemChunk u

GMemChunk* g_mem_chunk_new(gchar *name, gint atom_size,
                           gulong area_size, gint type);

Tato funkce vytvoří nový chunk ( GMemChunk) a vrátí pointer na něj. name je řetězec identifikující chunk. name není vnitřně kopírováno, mělo by proto existovat po celou dobu života GMemChunk u. Jak se dozvíte dále, slouží pouze k ladicím účelům – může být klidně NULL.

atom_size 

Argument type stanovuje typ chunku. Jsou přípustné dvě hodnoty tohoto parametru:

  • G_ALLOC_ONLY  – chunky tohoto typu umožňují pouze alokaci atomů. Uvolňování jednotlivých atomů z chunku není možné. Paměť se dealokuje najednou uvolněním celého  GMemChunk u.
  • G_ALLOC_AND_FREE  – atomy mohou být z chunku uvolňovány i jednotlivě (třeba funkcí g_mem_chunk_free()). Chunk si však musí vést dodatečné záznamy, což se projeví zvýšením spotřeby paměti a mírným poklesem rychlosti operací.

Alternativou vytvoření nového GMemChunk u je použití makra:

#define g_mem_chunk_create(type, pre_alloc, alloc_type) 

… které volá funkci g_mem_chunk_new() a vytvoří tak nový GMemChunk. type je typ atomů, které se budou v chunku skladovat – typicky jméno datové struktury nebo typu. Velikost atomu je zjišťována použitím sizeof(type). Velikost bloku se zjistí přenásobením parametru pre_alloc s velikostí atomu – pre_alloc je tedy počet atomů, které se vejdou do jednoho bloku. alloc_type musí být jedna z hodnot G_ALLOC_ONLY nebo G_ALLOC_AND_FREE (viz předchozí odstavec).

Jako jméno chunku se použije řetězec: "<type> mem chunks (<pre_alloc>)" přičemž místo <type> a <pre_alloc> se dá hodnota příslušného argumentu makra.

Příklad:

Následující volání g_mem_chunk_new() a g_mem_chunk_create() jsou ekvivalentní. Obě vytvoří nový chunk typu G_ALLOC_AND_FREE pro skladování proměnných typu MojeStruktura, přičemž délka bloku bude taková, aby se do něj vešlo 50 atomů

chunk = g_mem_chunk_new("MojeStruktura mem chunks",
  sizeof(MojeStruktura), 50 * sizeof(MojeStruktura),
  G_ALLOC_AND_FREE);

chunk = g_mem_chunk_create(MojeStruktura, 50, G_ALLOC_AND_FREE);

Práce s prvky (atomy)

gpointer g_mem_chunk_alloc(GMemChunk *mem_chunk); 

…použije část paměti v  GMemChunk u mem_chunk  k umístění jednoho prvku (atomu). Vrátí pointer na tuto položku.

gpointer g_mem_chunk_alloc0(GMemChunk *mem_chunk); 

…alokuje v  GMemChunk u mem_chunk  jeden atom a tuto paměť navíc vynuluje (všechny bajty nastaví na nuly). Vrácená hodnota je pointer na alokovaný atom.

#define g_chunk_new(type, chunk) 

Toto makro slouží také k alokaci atomu. Volá funkci g_mem_chunk_alloc() s argumentem GMemChunkchunk. Vrácenou hodnotu přetypuje na pointer na typ type.

#define g_chunk_new0(type, chunk) 

…volá funkci g_mem_chunk_alloc0() a jako argument jí předá GMemChunk chunk. Vrácená hodnota je ukazatel na vynulovaný atom, přetypovaný na pointer na typ type.

void g_mem_chunk_free(GMemChunk *mem_chunk, gpointer mem); 

…tato funkce se postará o uvolnění atomu, na nějž ukazuje pointer mem, z chunku mem_chunk. g_mem_chunk_free() by se měla používat pouze na GMemChunk typu G_ALLOC_AND_FREE. V opačném případě se nestane nic.

#define g_chunk_free(mem, mem_chunk) 

Makro g_chunk_free() je definováno pouze pro úplnost k makrům g_chunk_new() či g_chunk_new0(). Jednoduše předá parametry mem a mem_chunk funkci g_mem_chunk_free() (viz předchozí odstavec).

Ukončení práce s  GMemChunk em

voig g_mem_chunk_destroy(GMemChunk *mem_chunk); 

Uvolní veškerou paměť alokovanou pro GMemChunk mem_chunk.

ict ve školství 24

Příklad:

/* ukazkovy program pro pouziti GMemChunk */
#include<glib.h>
gint main(void)
{
  GMemChunk *chunk; /* nas mily chunk */
  gint x;
  gdouble *d[1000];

  chunk = g_mem_chunk_new("Nas chunk", sizeof(gdouble),
    100 * sizeof(gdouble), G_ALLOC_AND_FREE);
  /* vytvorime 1000 atomu typu gdouble... */
  for (x = 0; x < 1000; x++) {
    d[x] = g_chunk_new(gdouble, chunk);
    *(d[x]) = x / 2.0;
  }

  /* ...chvili s nimi pracujeme... */
  for (x = 0; x < 1000; x++) {
    printf("%lf ", *d[x]);
  }
  puts("\n");

  /* ...odstranime z chunku nektere z nich... */
  for (x = 100; x < 900; x += 2) {
    g_chunk_free(d[x], chunk);
  }
  /* ...a nakonec vsechno dealokujeme */
  g_mem_chunk_destroy(chunk);

  return(0);
}

Autor článku

Michal Burda vystudoval informatiku a aplikovanou matematiku a nyní pracuje na Ostravské univerzitě jako odborný asistent. Zajímá se o data mining, Javu a Linux.