OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 19 Март, 2024 08:07

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 15 ] 
Автор Сообщение
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 16:01 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
Вот, столкнулся с проблемой.
Есть модули подсистемы Lists, есть реализация двусвязного списка ListsIterable. Каждый из пары элементов ссылается друг на друга - сборщик мусора их не собирает.
Есть модуль XmlcoreDom, подсистемы Xmlcore - внутри копия ListsIterable плюс реализация спецификации DOM, где Node ссылается на всё что можно, итог - перекрёстные ссылки, сборщик мусора не собирает.

Сделал тестовый модуль с односвязным списком и оглядкой на сборщик - всё работает, отлично собирает. Смотрим на домены в Stores - оглядка на сборщик мусора. Смотрим на секвенсоры - оглядка на сборщик мусора.

Вот, такая проблема. Dom можно закапывать. А он уже используется в N проектах. То есть, можно говорить о том, что Dom с полями-ссылками концептуально не подходит для реализации в ББ. Dom с функциями-заменителями этих полей и оглядкой на сборщик проиграет в производительности.

Как-то так.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 17:15 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1447
Откуда: Киев
Сделал тестовый модуль с двусвязным списком - память собирается. Может дело не в этом, и где-то остаются "якоря", не дающие освободить память?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 17:59 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
код покажете?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 18:08 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Не может быть таких проблем.

Можно допустить проблемы, что заживается мусор в стеке, но ведь у вас не тот случай, в обычном графическом приложении выполняется сборка от главного оконного цикла, на пустом стеке. В общем, надо смотреть конкретно.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 18:28 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
я сужу по растущему значению Allocated memory во втором статус баре. И ещё заметно замедление работы фреймворка в целом.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 21:12 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1447
Откуда: Киев
Пётр Кушнир писал(а):
код покажете?

Код:
MODULE List;
   
   IMPORT  Out;
   
   TYPE
      List = POINTER TO RECORD
         prev, next: List;
      END;
      
   VAR
      list: List;
      creates: ARRAY 2 OF PROCEDURE (l: List): List;
      
   PROCEDURE CreateSingle(l: List): List;
   BEGIN
      NEW(l.next);
      RETURN l.next
   END CreateSingle;

   PROCEDURE CreateDouble(l: List): List;
   BEGIN
      NEW(l.next);
      l.next.prev := l;
      RETURN l.next
   END CreateDouble;

   PROCEDURE NewList(count: INTEGER; create: PROCEDURE (l: List): List): List;
      VAR l, n: List;
   BEGIN
      NEW(n);
      l := n;
      WHILE count > 0 DO
         l := create(l);
         DEC(count)
      END;
      Out.String("Ok"); Out.Ln;
      RETURN n
   END NewList;
   
   PROCEDURE Do*(method, count: INTEGER);
   BEGIN
      list := NIL;
      list := NewList(count, creates[method MOD 2]);
   END Do;

BEGIN
   creates[0] := CreateSingle;
   creates[1] := CreateDouble;
END List.

"List.Do(1, 10000000)"

Эксперименты показали, что выбор метода создания списка не влияет на освобождение памяти. Приложение затормаживается и самостоятельно не отдаёт память и так и так. Я чего-то не учитываю или ошибся?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 21:43 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
ну, если после инициализации выполнить Kernel.Collect, например через коммандер в логе - память очистится или нет? у меня на двусвязном не чистится, а на односвязном чистится.
Это двусвязный:
Код:
   TYPE
      IteratorItem* = POINTER TO ABSTRACT RECORD
         root: Iterator;
         prev-, next-: IteratorItem
      END;

      Iterator* = POINTER TO LIMITED RECORD(IteratorItem)
         first-, last-, this-: IteratorItem;
         length-: INTEGER
      END;

(** Итератор **)

   PROCEDURE (i: Iterator) Next* (), NEW;
   BEGIN
      ASSERT(i.this # NIL, 20);
      i.this := i.this.next
   END Next;

   PROCEDURE (i: Iterator) Prev* (), NEW;
   BEGIN
      ASSERT(i.this # NIL);
      i.this := i.this.prev
   END Prev;

   PROCEDURE (i: Iterator) First* (), NEW;
   BEGIN
      i.this := i.first
   END First;

   PROCEDURE (i: Iterator) Last* (), NEW;
   BEGIN
      i.this := i.last
   END Last;

   PROCEDURE (i: Iterator) Add* (item: IteratorItem), NEW;
   BEGIN
      ASSERT(item # NIL, 20);
      item.root := i;
      IF (i.last # NIL) & (i.first # NIL) THEN
         i.last.next := item;
         item.prev := i.last;
         item.next := NIL;
         i.last := item
      ELSE
         i.first := item;
         i.last := item;
         item.next := NIL;
         item.prev := NIL
      END;
      INC(i.length)
   END Add;

   PROCEDURE (i: Iterator) Remove* (item: IteratorItem), NEW;
   BEGIN
      ASSERT(item # NIL, 20);
      ASSERT(item.root = i, 21);
      IF item = i.this THEN i.this := NIL END;
      IF item = i.first THEN
         i.first := item.next;
         IF item.next # NIL THEN item.next.prev := NIL END
      ELSIF item = i.last THEN
         i.last := item.prev;
         IF item.prev # NIL THEN item.prev.next := NIL END
      ELSE
         item.next.prev := item.prev;
         item.prev.next := item.next
      END;
      item.next := NIL; item.prev := NIL; item.root := NIL;
      DEC(i.length)
   END Remove;

   PROCEDURE (i: Iterator) Insert* (this, before: IteratorItem), NEW;
   BEGIN
      ASSERT(this # NIL, 20);
      IF before = NIL THEN
         IF i.first # NIL THEN
            i.first.prev := this
         END;
         i.first := this
      ELSE
         ASSERT(before.root = i, 21);
         ASSERT(before # this, 22);
         this.root := i;
         this.prev := before.prev; IF before.prev # NIL THEN before.prev.next := this END; before.prev := this;
         this.next := before
      END;
      INC(i.length)
   END Insert;

   PROCEDURE (i: Iterator)Replace* (this, with: IteratorItem), NEW;
   BEGIN
      ASSERT(this # NIL, 20);
      ASSERT(with # NIL, 21);
      ASSERT(this.root = i, 22);
      ASSERT(with # this, 24);
      with.next := this.next;
      with.prev := this.prev;
      with.root := i; this.root := NIL; this.next := NIL; this.prev := NIL
   END Replace;

   PROCEDURE NewIterator* (): Iterator;
   VAR it: Iterator;
   BEGIN
      NEW(it);
      RETURN(it)
   END NewIterator;

Это односвязный:
Код:
TYPE
      List* = POINTER TO LIMITED RECORD
         length-: INTEGER;
         first, last: Item;
         p: Parent
      END;

      Parent = POINTER TO RECORD END;

      Item* = POINTER TO EXTENSIBLE RECORD
         p: Parent;
         _x: ANYPTR;
         next: Item
      END;

   PROCEDURE (i: Item) SetData (x: ANYPTR), NEW;
   BEGIN
      i._x := x
   END SetData;

   PROCEDURE (i: Item) GetData (): ANYPTR, NEW;
   BEGIN
      RETURN i._x
   END GetData;
   
   PROCEDURE (l: List) FINALIZE-;
   BEGIN
      l.last := NIL;
      l.first := NIL
   END FINALIZE;

   PROCEDURE (l: List) Last* (): Item, NEW;
   BEGIN
      RETURN l.last
   END Last;

   PROCEDURE (l: List) First* (): Item, NEW;
   BEGIN
      RETURN l.first
   END First;

   PROCEDURE (l: List) Next* (this: Item): Item, NEW;
   BEGIN
      ASSERT(this # NIL, 20); ASSERT(this.p = l.p, 21);
      RETURN this.next
   END Next;

   PROCEDURE (l: List) Prev* (this: Item): Item, NEW;
      VAR x, res: Item;
   BEGIN
      ASSERT(this # NIL, 20); ASSERT(this.p = l.p, 21);
      IF x # l.first THEN
         x := l.first;
         WHILE (x # NIL) & (res = NIL) DO
            IF x.next = this THEN res := x END;
            x := x.next
         END
      END;
      RETURN res
   END Prev;

   PROCEDURE (l: List) InsertAfter* (prev, this: Item), NEW; (* добавить this после prev, если prev=NIL, то в начало *)
   BEGIN
      ASSERT(this # NIL, 20); ASSERT(this.p = NIL, 21);
      IF prev # NIL THEN ASSERT((l.first # NIL), 22); ASSERT(l.p = prev.p, 23) END;
      IF (prev = NIL) & (l.first = NIL) THEN l.first := this; l.last := this
      ELSIF (prev = NIL) & (l.first # NIL) THEN this.next := l.first; l.first := this
      ELSE this.next := prev.next; prev.next := this END;
      IF prev = l.last THEN l.last := this END;
      INC(l.length); this.p := l.p
   END InsertAfter;

   PROCEDURE (l: List) Add* (this: Item), NEW;
   BEGIN
      ASSERT(this # NIL, 20); ASSERT(this.p = NIL, 21);
      l.InsertAfter(l.last, this)
   END Add;

   PROCEDURE (l: List) Remove* (this: Item), NEW;
      VAR prev: Item;
   BEGIN
      ASSERT(this # NIL, 20); ASSERT(this.p = l.p, 21);
      prev := l.Prev(this);
      IF prev = NIL THEN l.first := this.next
      ELSE
         prev.next := this.next;
         IF this = l.last THEN l.last := prev END
      END;
      DEC(l.length); this.p := NIL; this.next := NIL
   END Remove;
   
   PROCEDURE (l: List) Index* (this: Item);
   BEGIN
   
   END Index;
   
   PROCEDURE New* (): List;
      VAR l: List;
   BEGIN
      NEW(l); l.length := 0; NEW(l.p);
      RETURN (l)
   END New;
   
   PROCEDURE Join* (this, with: List): List;
      VAR x, x0: Item;
   BEGIN
      ASSERT(this#NIL, 20); ASSERT(with#NIL, 21); ASSERT(with#this, 22); ASSERT(this.p#with.p, 23);
      INC(this.length, with.length);
      x:=with.first;
      WHILE x#NIL DO
         x0:=x; x:=with.Next(x);
         x0.p:=this.p;
      END;
      IF this.first=NIL THEN this.first:=with.first
      ELSIF (this.last#NIL) & (with.first#NIL) & (with.last#NIL) THEN this.last.next:=with.first; this.last:=with.last END;
      with.length:=0; with.first:=NIL; with.last:=NIL;
      RETURN this;
   END Join;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 04 Апрель, 2011 22:17 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
вот говорят, что должно убирать
http://uniobox.i2p.to/log/oberon@confer ... 04#rep1192


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 05 Апрель, 2011 12:00 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Думайте, что может быть якорем. Вьюшка какая-нибудь, буфер обмена и т.п.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 05 Апрель, 2011 12:23 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2935
Откуда: г. Ярославль
Это и есть оглядка


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 05 Апрель, 2011 12:40 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2449
Откуда: Россия, Томск
Иван Кузьмицкий писал(а):
Это и есть оглядка

- А ну программируй отсюдова! - и он запрограммировал без оглядки.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 05 Апрель, 2011 13:16 

Зарегистрирован: Четверг, 08 Май, 2008 19:13
Сообщения: 1447
Откуда: Киев
Пётр Кушнир писал(а):
ну, если после инициализации выполнить Kernel.Collect, например через коммандер в логе - память очистится или нет? у меня на двусвязном не чистится, а на односвязном чистится.

Пробовал с Kernel.Collect - память чистится в любом случае.

Может стоит пройтись по всему списку и занулить все ссылки явно?


Последний раз редактировалось Comdiv Вторник, 05 Апрель, 2011 14:01, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 05 Апрель, 2011 13:51 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
И, кстати, подобный код бессмысленен:
Код:
   PROCEDURE (l: List) FINALIZE-;
   BEGIN
      l.last := NIL;
      l.first := NIL
   END FINALIZE;
Финализатор вызывается когда объект уже стал недоступным, чистить его поля уже не имеет смысла так как сборщик мусора никогда больше к ним не обратится.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 05 Апрель, 2011 16:21 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2662
Откуда: Россия, Ярославль
спасибо


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 05 Апрель, 2011 19:31 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8500
Откуда: Троицк, Москва
Пётр Кушнир писал(а):
вот говорят, что должно убирать
Должно. Это одна из фишек ББ вроде как, что должно.
У меня в одной из реализаций алгебраического движка были циклические списки, может, и щас есть. Всё собиралось, в масштабе гигов.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 15 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB