Менеджер памяти.
Пишу по-тихоньку оську, дошел до распределения памяти, как это в принципе реализуется?
Я просто вообще без понятия - хочу сделать таблицу идентификаторов владельца для каждой страницы, а уже детально каждую выделенную страницу расписывать в описывающей процесс структуре.
В этом и проблема-каким образом лучше и как помечать занятые места в странице?
Цитата: artyom-tyanutov
Я просто вообще без понятия - хочу сделать таблицу идентификаторов владельца для каждой страницы, а уже детально каждую выделенную страницу расписывать в описывающей процесс структуре.
у тебя все процессы находятся в одном адресном пространстве и как?
мне кажется лучше чтобы для каждого процесса своя память.
Цитата: artyom-tyanutov
.... а уже детально каждую выделенную страницу расписывать в описывающей процесс структуре.
для каждой физической страницы или виртуальной? а зачем детально?
Цитата: artyom-tyanutov
В этом и проблема-каким образом лучше и как помечать занятые места в странице?
ты наверно хотел спросить "как метить занятые страницы?"
мой мнение: держать в некоторой области физической памяти битовую карту всей физической памяти (где-нибудь в младших адресах), которую могут видеть все процессы и которая будет спроецирована на те же виртуальные адреса каждого процесса (так проще).
конкретнее вопрос надо задавать....
Просто целыми страницами каждый раз выделять это больно расточительно, поэтому надо как-то помешать сколько чего выделено в какой странице.
Только как лучше это сделать-разбить страницу на блоки или писать размер выделенного?
P.S. и тем более на всех нынешних более менее современных машинах стоит как минимум 256 МБ оперативки
Я думал менеджер памяти будет куда геморойнее!
А на счет того что ведь функции free передается просто адрес, то так как надо отмечать диапазон, чтобы корректно освободить их все, то я думаю вместо битовой карты использовать структуру с ролями описывающими владельца для каждой страницы и конец выделенного блока.
Как это делается на самом деле?
Но в мастдае и линухе выделенная память не кратна 0х1000 как было упомянуто-она кратна 16 байтам!
В ОС память выделяется так: если надо 16 байт, вэделяем страницу, а потом в специальной таблице пишем что в этой странице много яцеек по 16 байт, и когда следующий раз понядобится еще 16 байт, система заберет их уже из этой таблицы. В реале в линуксе выделится не 16 байт каздый раз, поскольку перед каждым блоком, который отдается программе, есть блок, в котором указан указатель на следующий пустой, если пустых нет, то он равен нулю.
В этом случае система при отстутствии пустых ячеек выделит еще одну страницу и указатель на нее запишет вместо этого нуля.
to artyom-tyanutov:
выделять память с точностью в 1 байт это глупо
Выделить память по конкретному адресу можно только страницами. Если выделать блоками, то перед блоком обычно идет 8 байт (реально надо 6, но это для выравнивания 8)
Выделение памяти приложению - высокий уровень.
Это разные уровни.
При последнем удобнее освобождать память после завершения процесса, но первое компактнее и узнать где чья страничка сложнее.
Можно поступить так: все, что выше какого-то адреса - владения ядра, все что ниже - владения пользователя. Это касается виртуальной памяти. При завершении процесса просто пройтись по PDE+PTE, которые относятся к пользователю и поудалять страницы виртуальной памяти. При удалении страниц виртуальной памяти сразу освобождать соответствующую им физическую память.
В этом случае можно просто ограничиться одной таблицей для физической памяти, в которой хранить занятость страницы и размер блока. Для занятых блоков во всех элементах прописывать "занято" (0x80000000), а для первого это значение еще OR`ить с размером блока. То же самое для свободных блоков, только без флага "занято". Для одного Гб физической памяти такая страница занимает 1 Мб, не так уж и много..
для совместно используемых страниц такой вид карты не прокатит .
Shared-страниц? В этом случае можно в дескрипторах страницы указать что она Shared, и создать счетчик исползования страницы, при освобождении из одного процесса уменьшать его на 1, когда он станет равным нулю освободить физическую память под эту страницу.
0- страница свободна ;
х<max - кол-во ниток использующих страницу ;
x>=max - специальные значения ;
старший бит - флаг разрешения перемещения страницы (чтоб не свопить ядро и драва :) ) ;
+ в таблице прописано количество тредов
- намного больше времени на выделение блоков физической памяти больше одной страницы
? и зачем флаг разрешения перемещения страницы ? Можно просто не свопать все верхние страницы памяти
что значит верхние - нижние ?
Под верхней памятью я имелл ввиду верхние адреса, те что не принадлежат пользовательским сегментам кода и данных.
зачем ядро в пользовательском пространстве вообще ?
Пора прекращать холивар, в принципе обсудили несколько вариантов нормальной организации памяти, и хватит.
если таблицы для каждого процесса разные , то это не обязательно .нечего делать ядру в адресном пространстве пользовательского процесса .
А монтировать страницы лучше по последнему не занятому адресу или куда попало, тоесть по физическому?
при страничной адресации и правильно сделаной карте памяти нет никакого дела до физического размещения .
Да я в курсе, имел в виду пусть какая-то прога запросила страницу памяти, в карте найду ее физический адрес, так вот ее монтировать по физическому адресу или по первому "пустому" виртуальному?
когда приложения пытается обратится к несуществующей странице происходит исключетие PF - ошибка страницы . в обработчик передаётся линейный адрес . по этому адресу определяеш место в таблицах куда и монтируеш страничку .
Байта хватит?
2) Известно что маллок перед выделенным блоком помещает 4 байта с указателем на следующий блок.
А как тогда помечать свободно/занято ведь указатель нужен один фиг?
Попробую предположить что можно это делать 7-м от 0 битом ведь например в мастдае 2 Гб максимум на прогу поэтому последний бит свободен.
Так?
А зачем помечать?? Есть массив(таблица), каждый его элемент - указатель на свободный блок заданного размера. В этом блоке первые 4 байта - указатель на следующий свободный блок, и.т.д в конце - ноль. Каждый элемент массива отвечает за список блоков определенной длины. Т.е. элементы массива будут для блоков длины 16, 32, 64, 128, 256, 512, 1024, 2048 байт. Для длин 4096+ память выделяется страницами в обход этой таблицы.
Занятые блоки не связаны в список, и у них эти 4 байта обозначают размер. Т.е. когда нужно удалить блок смотрим размер этого блока, потом вместо него записываем указатель, который хранится в таблице, а в таблицу вместо него ставим указатель на только что освободившийся блок.
Когда нужно выделить блок, берем тот блок, адрес которого сейчас в таблице, а вместо этого адреса в таблицу пишем значение первых четырех байт этого блока. А в первые четыре байта этого блока пишем его размер (16,32, ..., а не то, сколько программа попросила)
А если все блоки объединить в список а занятые помечать 7-ым битом как я сказал?
Так и расколоть блок без проблем если что можно, так на много проще, не тратится место под таблицу да и тормознее ли он вообще(проц'у я думаю пофиг по какому адресу mov'ать)?
В твоем методе один минус: когда надо будет удалить память, ты не будешь знать ее размера. Кроме того если у тебя будет одна цепочка для занятых, и одна для свободных, то очень много времени займет поиск свободного блока заданного размера... Очень неэффективно.
Тот способ, что я описал работает в этом плане намного эффективней.
Кроме того 32 байта на процесс (размер таблицы) не сильно нагрузит память ))
И я предлагал одну цепочку и для занятых, и для свободных блоков, поэтому размер я знать буду.
Спасибо всем, вроде написал что-то работающее