Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  17:25[Войти] | [Зарегистрироваться]
Ответ на вопрос № 42169

04-05-2006 01:43
DELPHI b OLE. Неужели все так плохо.
В Delphi есть проблема при работе с OLE - память после высвобождении объекта не очищается полностью. Что бы ты через это OLE не делал хоть выгрузки в Excel хоть под Word хоть под ADO, остаются куски памяти о которых программа не помнит.
МОЖЕТ БЫТЬ КТО-НИБУДЬ РЕШИЛ ЭТУ ПРОБЛЕМУ, ПРОШУ ПОВЕДАЙТЕ КАК ИМЕННО.
И как ни странно проблема есть, перерыл весь инет, а решения нет.
ЧТО ДЕЛАТЬ!!!!!!!!!!!!
Ну для примера

procedure SaveLog(FileName,Module,Event:String); stdcall;

const
//==============================================================
  adParamReturnValue=4; adParamInput=1;        adParamOutput=2;
//--------------------------------------------------------------
          adEmpty=0  ; adBoolean=11 ;          adTinyInt=16 ;
        adSmallInt=2  ; adInteger=3  ;          adBigInt=20 ;
adUnsignedTinyInt=17 ; adUnsignedSmallInt=18 ; adUnsignedInt=19 ;
  adUnsignedBigInt=21 ; adSingle=4  ;          adDouble=5  ;
        adCurrency=6  ; adDecimal=14 ;          adNumeric=131;
            adDate=7  ; adDBDate=133;          adDBTime=134;
    adDBTimeStamp=135; adFileTime=64 ;        adGUID=72 ;
          adError=10 ; adIUnknown=13 ;        adIDispatch=9  ;
        adVariant=12 ; adPropVariant=138;      adBinary=128;
            adChar=129; adWChar=130;            adBSTR=8  ;
        adChapter=136; adUserDefined=132;      adVarNumeric=139;
//==============================================================

Var Connection,
    Command  ,
    Res,
    Parametr1 ,
    Parametr2 ,
    Parametr3  :OLEVariant;
    Number:Integer;


  begin

// OleInitialize(nil);

  //----------------------------------------------
  if Assigned(ComObj.CoInitializeEx) then begin
              ComObj.CoInitializeEx(nil, COINIT_MULTITHREADED)
  end else begin    CoInitialize(nil);  end;

    TRY
      Connection := CreateOleObject('ADODB.Connection');
      Command    := CreateOleObject('ADODB.Command');
      Connection.Open('Driver={Microsoft dBase Driver (*.dbf)};Initial Catalog='+
      ExtractFileDir(FileName));
    EXCEPT
      Command    := UnAssigned;
      Connection := UnAssigned;
  CoUnInitialize; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      Exit;
    END;

  // Create base ---------------------------------------
  TRY
    if not FileExists(FileName) then begin
    Connection.Execute('Create TABLE  ' +
                        '"'+ExtractFileName(FileName)+'"'+
                        ' ('+
                        'NUMBER_  NUMERIC  ,'+
                        'Module  CHAR(20) ,'+
                        'Event  CHAR(240) '+
                        ' )');
    Connection.Execute('create index _NUMBER_ on "'+
                      ExtractFileName(FileName)+'" (NUMBER_)');
    end;
    EXCEPT
      Command    := UnAssigned;
      Connection := UnAssigned;
  CoUnInitialize; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      Exit;
    END;
  // Create base ---------------------------------------


  // Insert zapis to Table -----------------------------
  TRY
      Command.ActiveConnection := Connection;

      Command.CommandText:='SELECT MAX(NUMBER_) FROM '+ExtractFileName(FileName);
      Res:=Command.Execute;

      if VarIsNull(Variant(Res.Fields[0].Value)) then begin
          Number:=0;
      end else begin
          Number:=Integer(Res.Fields[0].Value)+1;
      end;

    Res.Close;

    Parametr1:=Command.CreateParameter('Nmb1', adInteger,adParamInput);
    Command.Parameters.Append(Parametr1);

    Parametr2:=Command.CreateParameter('Module', adChar,adParamInput,20 );
    Command.Parameters.Append(Parametr2);

    Parametr3:=Command.CreateParameter('Event', adChar,adParamInput,240 );
    Command.Parameters.Append(Parametr3);

    Command.CommandText:=
                    'INSERT INTO '+ExtractFileName(FileName)+
                    ' (NUMBER_,Module,Event) '+
                    ' VALUES  ( ?,?,? )';

  Command.Parameters[0].Value := Variant(Number);
  Command.Parameters[1].Value := Module;
  Command.Parameters[2].Value := Event;

  Command.Execute;

  Command.Parameters.Delete[2];
  Command.Parameters.Delete[1];
  Command.Parameters.Delete[0];

  EXCEPT
      Res        := UnAssigned;
      Parametr1  := UnAssigned;
      Parametr2  := UnAssigned;
      Parametr3  := UnAssigned;
      Command    := UnAssigned;
      Connection := UnAssigned;
  CoUnInitialize; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      Exit;
  END;

  // Insert zapis to Table -----------------------------

    Connection.Close;

      Res.Release;
      Parametr1.Release;
      Parametr2.Release;
      Parametr3.Release;
      Command.Release;

      Res        := UnAssigned;
      Parametr1  := UnAssigned;
      Parametr2  := UnAssigned;
      Parametr3  := UnAssigned;
      Command    := UnAssigned;
      Connection := UnAssigned;


// OleUninitialize;

  CoUnInitialize; //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //----------------------------------------------
  end;//SaveLog

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


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

09-05-2006 04:18 | Сообщение от автора вопроса
И все же проблема решаема или как. Кто нибудь еще поделиться мыслями.

05-05-2006 07:05
Идея была вот в чём
1.в COM управление по удалению объектов полностью возлагается на механизм подсчёта ссылок на объект, собственно методы
_AddRef и _Release это и делают
к тому же дельфи предоставляет автоматически генерируемый код по вызову этих методов

было предположение что при вызове

Command.Parameters.Append(Parametr2);


и им подобных

Command.Parameters например создаёт объект, а потом вызывается его метод Append
однако компилятор не вставляет пару методов _AddRef и _Release
соответственно объект не удаляется у него как был счётчик 0 так и остался.
2.
насчёт присвоения UnAssigned суть его в том что(да и любового другого присвоения переменной типа Variant) опять же при наличии в переменной указателя на интерфейс вызвать метод _Release (такое присвоение может быть необходимо для удаления объекта и соответственно используемой им памяти вручную или изменения порядка удаления объектов, однако аналогичный процесс происходит при выходе из области видимости переменной, в частности если она объявлена как локальная - выход из процедуры, как поле объекта - при удалении объекта).
3.
а вот использовать

SetProcessWorkingSetSize(GetCurrentProcess(), DWORD(-1), DWORD(-1));


наверное не очень хорошо, Винда, например, его делает при сворачивании окон. Это закидывает как уже сказали всю память процесса в СВАП. Заметьте всю - не только выделенную кодом внешних объектов, но и вашей программы а потом если что то понадобится вашей программе то будет производиться обратный процесс - чтение

05-05-2006 06:29 | Сообщение от автора вопроса
__ Shabal __
  SetProcessWorkingSetSize(GetCurrentProcess(), DWORD(-1), DWORD(-1));
Использование этой функции проге повредить не может. Проверено. Толку от неё мало. Все с оперативки валит в свап. Таким образом мы валим мусор в свап, свап растет. А он тоже не резиновый :-). Но польза все же есть - таким образом можно отодвинуть кончину программы на более долгий срок. :-)

__ Kealon __ Попробовал ваш совет. Не помогает. Но все равно хотелось бы узнать вашу догадку. Может она близка к истине. И на счет UnAssigned.
___ После использования Variant-a для очистки памяти :-) ему надо присвоить именно UnAssigned (гы гы гы), а не nil или другое значение,
т.к. nil в варианте это тоже значение. (не сам придумал, умные люди так пишут). Хотя в теории можно присвоить варианту, ну например Command:=1;
Так вот после такой операции Command должен очистить все что было раньше и перестроиться в другой тип ну например Integer; Т.Е.даже такая операция должна очищать память от объекта, на который Command ссылался раньше.

05-05-2006 05:30
а если по пробовать расписать

Command.Parameters.Append(Parametr3);


через


Parameters:Variant;
...
Parameters:=Command.Parameters;
Parameters.Append(Parametr3);


и все подобные выражения таким же образом (н-р:

Command.Parameters[0].Value := Variant(Number);

)
и UnAssigned присваивать смысла нет кажется
если это уменьшит утечку памяти, то я кажется знаю в чём причина

05-05-2006 00:17 | Сообщение от автора вопроса
------------------------------------------------
Люди ДОБРЫЕ есть еще предложения КАК
заставиь Delphi чистить память после COM-а.
Или для Delphi это KOM-a, причем клиническая :-)
------------------------------------------------

04-05-2006 21:27 | Сообщение от автора вопроса
__ Shabal __ Спасибо! Хорошо попробую использовать эту функцию.
SetProcessWorkingSetSize(GetCurrentProcess(), DWORD(-1), DWORD(-1));
Но использовать её боюсь весьма опасно можно свою прогу завалить, мне так кажется :-)


04-05-2006 07:01 | Комментарий к предыдущим ответам
Самое интересное что в VB аналог выше приведенного кода работает не пожирая память

Скорее всего у Майкрософт свои секреты на этот счет, а у Борланда свои мысли на счет рационального использования памяти (как известно у Борланда свой менеджер). Говорят помогает WinAPI'шная функция SetProcessWorkingSetSize(GetCurrentProcess(), DWORD(-1), DWORD(-1));

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/setprocessworkingsetsize.asp

04-05-2006 06:47 | Сообщение от автора вопроса
__ Shabal __ но решение этой проблемы быть должно, ведь безвыходных ситуаций не бывает _наверное_. Честно говоря я сначала написал подобие этого кода обращаясь к COM напрямую. Потом подумал что лучше перепишу на OLE, чтобы выглядело попроще :-).
__ Shabal __ а как бы еще __ Lingvo __ подключить к этому вопросу, может он подскажет что нибудь. Ты писал что он знает.
P/S/
Самое интересное что в VB аналог выше приведенного кода работает не пожирая память. :-)

04-05-2006 05:48 | Сообщение от автора вопроса
__ Shabal __ Сбасибо за ответ.
Но!!! Я не говорил, что OLE и COM это разные вещи. Это не разные вещи это одно и тоже, только механизм обращения разный. Я использовал за свою жизнь :-) два механизма обращения к COM? Binding а второй просто OLE не знаю уж как точно он там называется (наверное так и называется). Если писать через Binding работает быстрее, но кода нужно долбить больше. Так вот при использовании Binding память тоже утекает поверь мне, правда кушает меньше. Если не веришь попробуй, что нибудь простенкое соорудить и погонять.
Самое интересное можно просто сделать DLL например и ней создавать классами TADOConnction TADOQuery (эти классы тоже делают обращение на COM, правда имеют приятную оболочку) делать запросик ну там к dbf или к Excel-лу и разрушать их. Потом опять обращение к DLL-ке, и так в цикле.
Посмотри что будет. Твоё приложение начнет кушать память. И дело здесь в том, что Delphi криво работает с COM. Точнее чистит память после его использования. 


   

04-05-2006 05:25 | Комментарий к предыдущим ответам
это грубо говоря перейти на COM интерфейс, который просто уже описан, чтобы с ним проще было работать

На счет проще я бы поспорил... Библиотека типов TLB просто дает возможность "связвать" код с объектом OLE на этапе компиляции. Если вы думаете что COM это не OLE, то посмотрим что нам скажет Lingvo (а он знает!):

COM, Component Object Model [i]модель компонентных объектов Microsoft ( стандартный механизм, включающий интерфейсы, с помощью которых одни объекты предоставляют свои сервисы другим, - является основой многих объектных технологий, в том числе OLE и ActiveX )[/i]

Можно еще почитать здесь http://support.microsoft.com/default.aspx?scid=kb;en-us;245115

04-05-2006 05:18
Там практически все то же самое, но нужно в uses подключить ADOInt (библиотека типов ADO)


uses ComObj, ADOInt;
...
  Connect: _Connection;
  Cmd: _Command;
begin
  Connect := CreateComObject(CLASS_Connection) as _Connection;
  Connect.Open('Driver={Microsoft dBase Driver (*.dbf)};Initial Catalog=' + ExtractFileDir(FileName), 'user', 'pwd', adConnectUnspecified);
 
  Cmd := CreateComObject(CLASS_Command) as _Command;
  Cmd.Set_ActiveConnection(Connect);
...



В конеце не забудьте закрыть коннекшн и всем объектам присвоить nil, ноапр., Connect := nil;

И вам сой совет - не используйте имена типа Connection или Command - возможен конфликт с типами в ADOInt

04-05-2006 05:18 | Сообщение от автора вопроса
__Shabal__ Ранне связывание это я так понимаю подключить "библиотеку типов", ну это грубо говоря перейти на COM интерфейс, который просто уже описан, чтобы с ним проще было работать.
Вот например.
function ReaderADO.readADOSet(sSQLStatement: string): ADODB_TLB.Recordset;
var
  myConnection : ADODB_TLB.TConnection;
  rsResult : ADODB_TLB.Recordset;
  cmdCommand : ADODB_TLB.Command;
  myParameter : OleVariant;
begin
  myConnection := m_ConnectionPool.getADOConnection();
  cmdCommand := ADODB_TLB.CoCommand.Create( );
  cmdCommand.Set_ActiveConnection( myConnection.DefaultInterface );
  cmdCommand.CommandType := adCmdStoredProc;
  cmdCommand.CommandText := 'sp_DynamicRead';

    myParameter :=  VarArrayCreate([0, 4], varVariant);
    myParameter[0] := 'sql';
    myParameter[1] := 'adVarChar';
    myParameter[2] := 'adParamInput';
    myParameter[3] := sSQLStatement;

  rsResult := cmdCommand.Execute( oleRecords, myParameter, adCmdStoredProc );
    result := rsResult;
end;

Ну можно и не подключать библиотеку типов, а указать GUID необходимого COM-a, и обращаться к свойствам и методам почитав о них MSDN (в случае с ADODB), так я тоже делал. (В инете есть куча примеров по этому поводу) Результат тотже - ПАМЯТЬ ТЕЧЕТ. Тоже самое. Все плохо, ничего не помогает.
____________________________________________________________
Может ты делаешь это как то по особенному. Напиши пожалуйста.

04-05-2006 04:21 | Сообщение от автора вопроса
__Shabal__ А можно пример. Пожалуйста. Очень нужно.

04-05-2006 03:54 | Комментарий к предыдущим ответам
так вот скажу вам по секрету, мало того, что от утечки памяти это не помогает, так вот иногда даже процесс excel.exe остается висеть в памяти. Я думаю, что и с таким глюком люди тоже сталкивались.

Конечно сталкивались! И скажу вам по секрету, что сталкиваются обычно те, кто использует позднее связывание :D

ЗЫ К стати, в вашем случае при работе с ADO можно запросто выйти на раннее связывание

04-05-2006 03:19 | Сообщение от автора вопроса
Я привел код, который кстати работает.
Как видите ___Erika___  Unassigned там присутствует и Release на прозапас тоже. Но это не помогает. Проверьте. А на счет __quit__ это для Excel, так вот скажу вам по секрету, мало того, что от утечки памяти это не помогает, так вот иногда даже процесс excel.exe остается висеть в памяти. Я думаю, что и с таким глюком люди тоже сталкивались.

А вообще ___Erika___, прогоните свой код  10 000 раз, и посмотрите, сколько съел оперативки ваш процесс. Если утечки нет очень бы хотелось бы увидеть этот кусок кода. Был бы очень признателен.

04-05-2006 01:49
Unassigned; или quit(); проблем не было

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Какой месяц идет после марта?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования