Как составить программу для памяти

Проектная работа «Разработка и создание игры для развития памяти на Python c помощью библиотеки Pygame»

Автор:

Тян Олеся Девоновна

учащаяся 10 Г класса МБОУ СОШ № 22

Самутенко Любовь Анатольевна

учитель информатики МБОУ СОШ № 22

Проектная работа «Разработка и создание игры для развития памяти на Python c помощью библиотеки Pygame»

Написание собственного неплохого менеджера памяти

Время на прочтение
4 мин

Количество просмотров 14K

Доброе время суток, читатель. Возможно, вы уже читали мои предыдущие статьи, и знаете, что я занимаюсь написанием собственной ОС. Сегодня мы поговорим, и рассмотрим несложный и достаточно быстрый алгоритм для управления памятью — менеджер памяти — критически важная часть ОС, ведь быстрая, надежная и нерастратная работа с памятью залог хорошей ОС.
Искал я несложные и адекватные идеи для менеджера и в рунете, и на англоязычных сайтах — всё никак не мог найти никаких хороших статей про адекватный, работающий не за O(N) аллокатор. Что же, сегодня мы рассмотрим более хорошую идею для менеджера памяти, продолжение помещаю под кат.

Теория

Из вики: Менеджер памяти — часть компьютерной программы (как прикладной, так и операционной системы), обрабатывающая запросы на выделение и освобождение оперативной памяти или (для некоторых архитектур ЭВМ) запросы на включение заданной области памяти в адресное пространство процессора.

Предлагаю так же перед продолжением прочитать эту статью.

Watermak Allocator

Что же, наверное самый простой из всех аллокаторов — Watermark Allocator. Суть его примерно следующая: вся память разбита на блоки, у блока есть заголовок, в котором лежит размер этого и предыдущего блока, статус блока(занят/свободен), зная адрес блока мы за O(1) можем получить адрес следующего и предыдущего блока.

Выделение памяти

Для выделения памяти нам просто напросто нужно бежать по блокам, и искать блок, размер которого больше или равен размеру требуемой для выделения памяти. Как вы уже поняли, асимптотика O(N) — плохо.

Высвобождение памяти

Для высвобождения памяти нам достаточно установить статус блока как «свободный» — O(1) — супер!

Но, как вы понимаете, могут начать образовываться дыры, в которых 2 и более свободных блоков — память дефрагментированна, при высвобождении можно просматривать соседние блоки, и в случае, когда один или два свободны — мержить их в один.

Аллокатор за логарифмическую скорость

Мы знаем, что нам надо искать только среди свободных блоков. Бегать только по свободным улучшает скорость в среднем в два раза, но это всё равно линия. Что же, зачем нам бегать по всем блокам, ища размер, если мы можем организовать дерево из свободных блоков! Изначально у нас только один свободный блок, а дальше мы добавляем свободные блоки в бинарное дерево поиска, ключом будет — размер блока. Таким образом, чтобы выделить память нам достаточно найти блок в дереве, у которого размер больше или равен тому, что нам нужен. Это мы спокойно делаем за O(log N), просто спускаясь по дереву вниз. Дальше мы либо режем блок на два, либо полностью отдаем его тому, кто запросил память. Дальше мы удаляем блок из дерева за O(1). И, если надо, вставляем оставшуюся часть блока обратно за O(log N). Для высвобождения нам достаточно вставить блок обратно, и не надо забывать про фрагментацию.

Логично, что использовать простое дерево не надо, надо использовать самобалансирующееся дерево, Red-Black или AVL. Хранить дерево блоков можно в статическом массиве, или же придумать как это сделать по-другому.

Собственно, код:

char * malloc(size_t size) {
	if (!size) {
		return 0;
	}
	char * addr = 0;
	int i;
	for (i = 0; i < allocationAvlTree.size; )
	{
		int r;
		node_t *n;
		n = &allocationAvlTree.nodes[i];
		/* couldn't find it */
		if (!n->key) {
			return NULL;
		}
		r = allocationAvlTree.cmp(n->key, size);
		if (r <= 0)
		{
			//We're lucky today.
			//Get memory block header
			alloc_t * block = (size_t)n->val - sizeof(alloc_t);
			//Set to used
			block->status = 1;
			//Set size
			block->size = size;
			alloc_t * next = (size_t)n->val + size;
			next->prev_size = size;
			next->status = 0;
			next->size = n->key - size - 16;
			avltree_remove(&allocationAvlTree, n->key, n->val);
			if (n->key - size - 16)
				avltree_insert(&allocationAvlTree, next->size, (size_t)next + sizeof(alloc_t));
			memset((size_t)block + sizeof(alloc_t), 0, block->size); 
			block->signature = 0xDEADBEEF;
			unlockTaskSwitch();
			return (size_t)block + sizeof(alloc_t);
		}
		else if (r > 0)
			i = __child_r(i);
		else
			assert(0);
	}
	return 0;
}

void free(void * mem) {
	if (!mem)
		return;
	//Get current alloc
	alloc_t * alloc = ((unsigned int)mem - sizeof(alloc_t));
	if (alloc->signature != 0xDEADBEEF)
		return;
	alloc->status = 0;
	alloc_t * left = ((unsigned int)alloc - sizeof(alloc_t) - alloc->prev_size);
	if (left->signature == 0xDEADBEEF&&left->status == 0&&left->size==alloc->prev_size)
	{
		//Merge blocks
		if (avltree_remove(&allocationAvlTree, left->size, (uint)left + sizeof(alloc_t))) {
			left->size += sizeof(alloc_t) + alloc->size;
			alloc = left;
		}
		else assert(0);
	}
	alloc_t * right = (uint)alloc + sizeof(alloc_t) + alloc->size;
	if (right->prev_size&&right->status == 0&&right->signature == 0xDEADBEEF)
	{
		if (avltree_remove(&allocationAvlTree, right->size, (uint)right + sizeof(alloc_t)))
			alloc->size += sizeof(alloc_t) + right->size;
		else assert(0);
	}
	avltree_insert(&allocationAvlTree, alloc->size, (uint)alloc + sizeof(alloc_t));

}

Удачи и этичного хакинга! Любая объективная критика приветствуется, цель статьи не сказать, что это вах какой аллокатор, а просто рассказать о аллокаторе, который будет лучше, чем тупые реализации простых аллокаторов.

Формулировка задачи:

Составить програмМу для тренировки памяти. ПрограмМа должна высветить на экране несколько точек, играющий — указать, в каком порядке эти точки были высвечены. Координаты точек выбираюТСя в програмМе с помощью датчика случайных чисел. ВОТ что у меня получилось:

в строке OutTextXY(x,y,a[i]); я хочу что бы на экран выводило числа масСива, как это сделать, кто-то мне сказал перевести в стринг что-то, но я нчиего не понял…

Код к задаче: «ПрограмМа чтОБы тренИровать память»

textual

function IntToStr(I: Longint): String;
{ Convert any integer type to a string }
var
S: string[11];
begin
Str(I, S);
IntToStr := S;
end;

Полезно ли:

6   голосов , оценка 3.833 из 5

Я немного изменил идею, теперь возникла проблема, и если поможете ее решить задачу будет сделана.
Я хочу что бы внутри шарика который появляется ставилась цыфра, которая рандомом записалась в масив, но не получаеться, вот код.
uses crt,Graph;

var

grDriver: Integer;
grMode: Integer;
ErrCode: Integer;
a:array [1..100] of integer;
i,n,x,y:integer;
begin
Writeln(‘Џ®б«Ґ **¦*вЁп Є«*ўЁиЁ Enter, ўўҐ¤ЁвҐ Є®«ЁзҐбвў® и*аЁЄ®ў.’);readln;
grDriver := VGA;
grMode:= VGAHi;
InitGraph(grDriver, grMode,»);
randomize;
SetBkColor(9);
SetLineStyle(CenterLn,0,ThickWidth);
Writeln(‘vvedit kilkist warikiv’);readln(n);
for i:=1 to n do
a[i]:=random(50);
for i:=1 to n do begin
x:=random(550)+random(20);
y:=random(450)+random(20);
circle(x,y,20);
OutTextXY(x,y,’2′);
delay(50000);
end;
delay(50000);
delay(50000);
cleardevice;
readln;
CloseGraph;

end.

 

В Си работать с динамической памятью можно при помощи соответствующих функций распределения памяти (calloc, malloc, free), для чего необходимо подключить библиотеку
malloc.h

С++ использует новые методы работы с динамической памятью при помощи операторов new и delete:

  • new — для выделения памяти;
  • delete — для освобождения памяти.

Оператор new используется в следующих формах:

  • new тип; — для переменных
  • new тип[размер]; — для массивов

Память может быть распределена для одного объекта или для массива любого типа, в том числе типа, определенного пользователем. Результатом выполнения операции new будет указатель на отведенную память, или исключение std::bad_alloc в случае ошибки.

int *ptr_i;
double *ptr_d;
struct person *human;

ptr_i = new int;
ptr_d = new double[10];
human = new struct person;

Память, отведенная в результате выполнения new, будет считаться распределенной до тех пор, пока не будет выполнена операция delete.

Освобождение памяти связано с тем, как выделялась память – для одного элемента или для нескольких. В соответствии с этим существует и две формы применения delete:

  • delete указатель; — для одного элемента
  • delete[] указатель; — для массивов

Например, для приведенного выше случая, освободить память необходимо следующим образом:

delete ptr_i;
delete[] ptr_d;
delete human;

Освобождаться с помощью delete может только память, выделенная оператором new.
Пример Создание динамического массива

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

#include <iostream>
using namespace std;
int main()
{
  int size;
  int *dan;
  system(«chcp 1251»);
  system(«cls»);
  cout << «Ввести размерность массива : «;
  cin >> size;
  dan = new int[size];
  for (int i = 0; i<size; i++) {
    cout << «dan[» << i << «] = «;
    cin >> dan[i];
  }
  for (int i = 0; i<size; i++)
    cout << dan[i] << » «;
  delete[] dan;
  cin.get(); cin.get();
  return 0;
}

Результат выполнения
Операторы new и delete

Указатель dan – базовый адрес динамически распределяемого массива, число элементов которого равно size. Операцией delete освобождается память, распределенная при помощи new.

Пример неудачного выделения памяти (в случае очень большого требуемого объема):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include <iostream>
using namespace std;
int main()
{
    int *p = 0;
    try
    {
         p = new int[1000000000];
    }
    catch(const bad_alloc& e)
    {
        cout << «Error: « << e.what() << ‘n’;
    }
    cout << p << endl;
    return 0;
}

Назад: Язык C++

Понравилась статья? Поделить с друзьями:
  • Как найти свой номер вин
  • Как составить рабочий график при 12 часовом рабочем дне
  • Avlaunch exe ошибка приложения как исправить
  • Как найти корень квадратного уравнения если дискриминант
  • Как найти выданное разрешение на строительство