Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.03.05;
Скачать: [xml.tar.bz2];

Вниз

Что там 2200 потоков ...   Найти похожие ветки 

 
TUser   (2004-02-24 18:48) [0]

Ура, форум работает ...
Вот такой вопрос.

Пишу парсер. При парсинге создается некоторая разветвленная структура объектов, кот орые представляют описание различных уровней некоторой структуры. Проблема в том, что на самом нижнем уровне объектов много - максимально возможное их число из спецификаций формата равно 99999 для одной модели, а таких моделей там м.б. несколько. Реально обычно меньше - тысяч 10-40 на весь файл. Но столько много объектов создать не удается. Реально примерно на конце пятой тысячи объектов при попытке выполнить конструктор возникает Access violation. Пишет, что нельзя обращаться по адресу 000...010. В исходном файле, который используется для парсинга на том месте, где происходит бряк ничего подозрительного нет.

Памяти на хранение всего вот этого должно хватать - если ее не хватит, так пусть он свопится, а не AV выдает. Смущает низкое значение адреса, по которому происходит попытка обратиться - может быть заполнился весь доступный для чего-то объем памяти, причем этот объем организован циклически? Не знаю. Стек там большой, и вообще он тут вроде бы не при чем, кроме того я его увеличивал - и никакого результата.
Как можно решить такую проблему? Очень хотелось бы отыскать решение, которое не требует изменения архитектуры проекта, т.е. отыскать способ создать соотв. количество объектов, а не способ организовать проект без такового создания.

Конструкторы выглядят примерно так. На каждом уровне написано
constructor Create(Parent:TParent);
begin
FObjectOfUpperLevel:=Parent;

FFirst:= ...;
FSecont:= ...;

// И еще иногда устанавливаются размеры массивов

setLength(FArray,FArLewngth);
end;


Далее там есть методы типа
procedure AddChildObject;
begin
inc (FArLength);
setLength(FArray, FArLength);
Farray[FArLength-1]:=TChildObject.Create(Self);
end;


Вот так все это создается, но в какой-то момент выскакивает AV. Тут точно что-то с памятью, но ума не приложу - что именно. Выскакивает на конструкторе, который уже много раз нормально отработал, создано уже много объектов данного класса, но на создании очередного объекта он брякается.

Пока форум не работал пытался задавать этот вопрос на других конфах. На алголисте мне CD_Eater посоветовал следующее
>Проблема в Борландовском менеджере памяти.
Простой пример: взять 100 Мбайт памяти одним куском памяти получится без проблем, а вот если память брать кусочками по несколько байт, то через несколько тысяч таких кусочков их запас иссякнет, хотя использована едва ли десятая часть всей доступной памяти, даже с учётом округления до 16 байт.
Я выходил из этой ситуации написанием своего "менеджера памяти" - брал память напрямую у Windows (кусками порядка 8 Мбайт) и разделял её на маленькие кусочки самостоятельно. По-моему, в Delphi даже предусмотрены специальные функции для замены стандартного борландовского менеджера памяти пользовательским.


На королевстве мой вопрос так и не появился. Там с полудня сегодня ничего нового не повилось, по наблюдениям. Надеюсь на Вашу помощь. Скажите, что это за функци для замены борландос\вского менеджера памяти, как их юзать и гду у борланда вообще про юто можно прочитать.

Система - Win2000Pro либо ХРPro (от системы это не зависит), памяти 128К, места на харде навалом. Спасибо.


 
Игорь Шевченко   (2004-02-24 18:49) [1]

А что говорит отладчик ?


 
Тимохов   (2004-02-24 18:54) [2]

Про то, что у дельфи плохой менеджер памяти, есть гон.
У нас было до 2 млн. объектов в дереве. Все работало на ура.
Если есть АВ, есть ошибка и никак иначе - менеджер тут ни при чем.


 
TUser   (2004-02-24 19:07) [3]

Отладчик говорит так. Есть метод AddChild. Как только он вызывается - AV, хотя там совершенно безобидный код

inc (FProp); // <-- AV

Вызывается метода так

with Obj.Obj. ... .Obj[obj.obj. ... .AddChild] do begin
...
end;
При этом AddChild возвращает номер добавляемого объекта, которые организованы в виде массива
private
FArray:Array of Obj;

procedure rAr(Index:integer):TObj;

property Ar[Index:integer]:TObj read rAr;

procedure rAr(...):TObj;
begin
if {Index имеет допустимое значение}
then result:=FAr[Index]
else raise ...
end;

Соотв. если я в AddChild защищаюсь через try ... except, то получаю AV в строке, коорая идет после with.

PS. Про то, что менеджер памяти хороший и можно создавать до чертовой прорвы объекто - это хорошие новости, thanks.


 
Defunct   (2004-02-24 19:12) [4]

> У нас было до 2 млн. объектов в дереве. Все работало на ура.
Ради интереса, создал 40 тыс. объектов, в каждый из которых входит массив TBitmap от 5-то до 20. Суммарно около 400 тыс. экземпляров объектов. Никакого AV не наблюдается. Тормозит правда жутко, но AV нет.


 
Игорь Шевченко   (2004-02-24 19:12) [5]

offtopic, но:

а что стоит за многоточиями в

> with Obj.Obj. ... .Obj[obj.obj. ... .AddChild] do begin
>


?


 
Тимохов   (2004-02-24 19:13) [6]


> inc (FProp); // <-- AV

Это не безобидный код, если ты вызываешь метод объекта nil.
Просто идет обращение к полям не созданного объекта. Вот и ошибка.

Чему равен self перед этим inc(fprop)?


 
Defunct   (2004-02-24 19:18) [7]

Может ошибка тут:
Obj[obj.obj. ... .AddChild]
Не верный номер..
IMHO AddChild лучше бы возвращал ссылоку на объект. чтобы писать
With AddChild() do..


 
icWasya   (2004-02-24 19:20) [8]

скорее всего глюк здесь

procedure AddChildObject;
begin
inc (FArLength);
setLength(FArray, FArLength); // <<<==========!!!!!!!!=
Farray[FArLength-1]:=TChildObject.Create(Self);
end;

посмотри, как организован TList - там нигде не используется
setLength(FArray,Length(FArray)+1)

попробуй так

const Capacity =10000;
procedure AddChildObject;
begin
inc (FArLength);
if Length(FArray)<=FArLength then
setLength(FArray, Length(FArray)+FCapacity); // !!

Farray[FArLength-1]:=TChildObject.Create(Self);
end;


 
TUser   (2004-02-24 19:20) [9]

Нет. Объект точно есть. В него уже добавлялось несколько (7 штук) таких объектов. Т.е. self <> nil. Т.е. есть много объектов этого уровня (куда добавляем). Во многие из них все добавляется нормально. Но только в некоторый момент AddChild начинает глючить.

За многоточиями стояит описание множества вложенных бъектов. Конкретно это выглядит так
with FChains[ch-1].Models[FParsingModel-1].Residues[rNum-1].Atoms[j] do
Т.е. есть белок (объект класса TProtein), у него есть несколько цепей (TChain, массив FChains), там есть модели (TModel, FMoleds), далее - остатки (TResidue, FResidues), у каждого остатка - свои атомы (TAtom, массив FAtoms). Всего вплоть до остатков - не очень много. Но, атомы как-то плохо себя ведут.


 
Тимохов   (2004-02-24 19:23) [10]


> Т.е. self <> nil.

Это еще не гарантия того, что объект реально создан.
procecure do;
var
o: TObject;
begin
o.somemethod; // не конструктор. может быть ав, а может и не быть, но self скорее всего будет не nil
end;


 
Defunct   (2004-02-24 19:28) [11]

> Нет. Объект точно есть.
Зачем же так категорично.. Раз AV значит объекта нет.

FChains[ch-1].Models[FParsingModel-1].Residues[rNum-1].Atoms[j]
Если в этой цепочке хотя бы один из индексов будет ошибочным, то выскочит AV


 
Тимохов   (2004-02-24 19:30) [12]


> FChains[ch-1].Models[FParsingModel-1].Residues[rNum-1].Atoms[j]
>
> Если в этой цепочке хотя бы один из индексов будет ошибочным,
> то выскочит AV

Скорее range check error будет...


 
Vuk   (2004-02-24 19:30) [13]

Если объектов много и происходят частые вставки, то, возможно, спасет использование списочных структур вместо массивов. Минус - замедление доступа, если он индексный. При последовательном переборе - по барабану. Зато вставка более быстрая и не требует дополнительной памяти.


 
TUser   (2004-02-24 19:31) [14]

Индексы еще раз проверю. Но много раз все выполняется нормально - ошибка выскакивает только на достаточно большом номере атома.

Совет icWasya [8] проверил - стал добавлять в setLength порциями, ничего не изменилось.


 
TUser   (2004-02-24 19:35) [15]

Индексы точно правильные. Уверен.


 
Тимохов   (2004-02-24 19:36) [16]


> TUser © (24.02.04 19:31) [14]

Еще раз - не ищите ошибку в менеджере памяти, ищите ошибку у себя. У вас однозначно есть обращение к полям несозданного объекта. Можете, например, во всех конструкторах поставить добавление self в некий глобальный list. Потом, при обращение к объекту проверять, чтобы этот объект был в списке. Если нет, то значит ошибка.


 
Defunct   (2004-02-24 19:37) [17]

Тимохов © (24.02.04 19:30) [12]
??????
Какой Range check?? Это же динамические массивы, не может там быть никаких Range Check.


 
TUser   (2004-02-24 19:39) [18]

2 Vuk
Нет вставок не происходит. Все элементы добавляются в конец списка, т.е.
inc(FCount)
setLength(Array, FCount);
Array[FCount-1]:=FObj.Create(Self);
или по совету [8] c тем же результатом


 
Defunct   (2004-02-24 19:40) [19]

Все-таки
> FChains[ch-1].Models[FParsingModel-1].Residues[rNum-1].Atoms[j]
смотрится не очень красиво, зачем объекту на текущем уровне знать о существовании предка в 10-м колене?..


 
Тимохов   (2004-02-24 19:40) [20]


> Defunct © (24.02.04 19:37) [17]

Да что вы говорите!!!
Я вижу вы как крутой уже в параметрах проекта отключаете range check error!!!
Респект!!!


 
Vuk   (2004-02-24 19:41) [21]

to TUser:
>Нет вставок не происходит. Все элементы добавляются в конец
>списка
А какая разница? Все равно память перераспределяется.


 
TUser   (2004-02-24 19:42) [22]

Он не знает. Он знает ссылку на своего папу на один уровень выше. Конечно, если потребуется может до самого верха добраться по таким ссылкам.


 
Тимохов   (2004-02-24 19:43) [23]


> TUser © (24.02.04 19:42) [22]

Посмотрите совет из 16. Вы так сможете проверить есть ли у вас действительно обращение к несозданным объектам.


 
Тимохов   (2004-02-24 19:57) [24]

Еще можете range check error включить (если отключен).


 
Defunct   (2004-02-24 20:11) [25]

2 TUser
Вы привели AddChild полностью, а можно взглянуть на конструктор тоже полностью?

2 Тимохов
Да действительно, Range check выключен был постоянно.


 
Vuk   (2004-02-24 20:20) [26]

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

TNode = class
public

property Next: TNode ...;
property Parend: TNode ... ;
property FirstChild: TNode ...;

end;

Это односвязный список. Можно двусвязный сделать...


 
Defunct   (2004-02-24 20:26) [27]

Да, как вариант могу предложить сделать авто-парсер, каждый объект считывает из файла только ту часть которая необходима для инициализации только его полей. И создать перекрываемую функцию CreateKnownObject, для создания объекта нужного типа.

Вот как вариант, кусочек из готового проекта:

TCluster = Class(TDrawCollection)

Procedure CreateKnownObject(ObjectType:Byte);Override;
Procedure ConfigureKnownObject(DrawComponent:TDrawComponent);Override;
Function NewObject:TDrawComponent;Override;
...

Procedure Save(Var F:File);Override;
Procedure Load(Var F:File);Override;
End;

Procedure TCluster.CreateKnownObject;
Begin
Inherited;
Case ObjectType Of
ot_ComputingUnit : Item := TComputingUnit.CreateFixed(C, DBox);
ot_DuplexLink : Item := TDuplexLink.CreateFixed(C, DBox);
ot_Cluster : Item := TCluster.CreateFixed(C, DBox);
End;
End;

Procedure TCluster.ConfigureKnownObject;
Var I:Integer;
Begin
Inherited;
Case DrawComponent.ObjectMap.ObjectType Of
ot_ComputingUnit :
Begin
For I:=0 To Template.VSCount-1 Do
(DrawComponent As TGraphicTop).
AddViewStyle( Template.ViewStyles[i]);
(DrawComponent As TCustomDrawObject).StyleIndex := 0;
(DrawComponent As TCustomDrawObject).SelStyleIndex := 1;
(DrawComponent As TComputingUnit).AddInfoOnTheGlyph(0);
(DrawComponent As TComputingUnit).AddInfoOnTheGlyph(1);
End;
ot_DuplexLink :
Begin
(DrawComponent As TGraphicLink).OnObjectRequest := RequestID;
End;
ot_Cluster : ;
End;
End;

Procedure TCluster.Save;
Begin
Inherited;
End;

Procedure TCluster.Load;
Begin
Inherited;
End;


 
TUser   (2004-02-24 22:32) [28]

Вот разобрался. Дело было в определенных спецификациях формата. Я некоторые вещи не учел, поэтому происходил сбой в индексах. Грубо говоря, есть X остатков, на Х/2 происходил сбой, делее все индексы считались на некоторую величину больше, чем надо. Поэтому ближе к концу происходило обращение к несуществующему объекту. Так что всем thanks.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2004.03.05;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.008 c
3-12237
lucky4me
2004-01-29 13:48
2004.03.05
TDBGrid: Как выделить строку программным путем?


1-12436
Alexey
2004-02-23 12:55
2004.03.05
Как узнать содержимое папки?


1-12358
Builder
2004-02-25 10:47
2004.03.05
файлы


1-12357
dm37
2004-02-25 15:04
2004.03.05
time


14-12483
TUser
2004-02-13 14:05
2004.03.05
технологии





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский