ADO. Recordset. Повышенный расход памяти.
От: Кривов Сергей Владимирович Россия  
Дата: 07.03.03 08:12
Оценка:
Уважаемые коллеги!
Есть COM-компонент (FWDBSet), использующийся для доступа к данным в SQLServer-е через комбинацию OLEDB-ADO (чистый OLEDB используется для получения сессии из пула коннектов и более быстрого создания и открытия Rowset-а, а для доступа к полям rowset-а используется ADORecordset). Компонент работает под dllhost-ом и для тестовых программ, описанных ниже, доступен как OutProc — компонент. Эти две тестовые программы создают и открывают по 100 DBSet-ов, одна из них написана на C++, вторая — на JS (на VBS эффект тот же). После исполнения программы на C++ размер памяти dllhost-а остается практически неизменным, после JS — вырастает на 25Мб. Исследования показали, что причиной роста является работа следующего куска кода (для краткости опущены проверки) в том месте, где создается ADORecordset через ADORecordsetConstruction:
void CFWDBSet::CreateRecordset(tstring strSQL)
{
    CFWDBConnectionSupplier spConnSuppl;
    CComPtr<IUnknown> spSessUnk = spConnSuppl.CreateSession(m_lStorageID);
    CComQIPtr<IOpenRowset> spOpenRowset = spSessUnk;

    CDBPropSet propset(DBPROPSET_ROWSET);
    propset.AddProperty(DBPROP_IRowsetChange, false);
    propset.AddProperty(DBPROP_IRowsetUpdate, false);
    propset.AddProperty(DBPROP_CLIENTCURSOR,false);

    strSQL.MakeUpper();
    bool bBind = true;
    if(strSQL.Find(strSELECT) == -1)
        bBind = false;

    CSession sess;
    sess.m_spOpenRowset = spOpenRowset;
    
    CCommand<CDynamicAccessor> rs;
    // Open but don't bind.
    HRESULT hr = rs.Open(
        sess, 
        strSQL,
        &propset, 
        NULL,
        DBGUID_DBSQL,
        bBind);

    if(m_spRs==NULL) m_spRs.CreateInstance(__uuidof(Recordset));    

    ADORecordsetConstructionPtr adoRsConstruct = NULL;
    m_spRs->QueryInterface(__uuidof(ADORecordsetConstruction),(void**)&adoRsConstruct);

    IUnknownPtr spUnk = NULL;
    rs.m_spRowset->QueryInterface(IID_IUnknown, (void**)&spUnk);
    adoRsConstruct->put_Rowset(spUnk);
}


А вот и коды тестовых программ (в методе GetFirst осуществляется собственно открытие DBSet-а и там выполняется приведенный выше код)

    for(int i=0;i<100;i++)
    {
        SP::IFWSetPtr spSet = FWCreateDBSet(testAT); // создается новый экземпляр DBSet-а под dllhost-ом
        SP::IFWDBSetPtr spDBSet = spSet;
        SP::IFWIteratorPtr spIt = spSet->GetIterator();
        spIt->GetFirst();
    }



    var spSet;
    var spIt;

    for(i = 0; i < NumIter; i++)
    {
        spSet = spSrv.CreateDBSet("SELECT OID FROM TestCompoundAttr1", "1"); // создается новый экземпляр DBSet-а под dllhost-ом
        spIt = spSet.GetIterator();
        spIt.moveFirst();
        delete spSet;
        delete spIt;
    }

Процедура создания Recordset-а через ADORecordsetConstruction — один в один из MSDN. Версия MDAC — 2.70.9001.0. Помогите пожалуйста советом, хотя бы в какую сторону копать!
Заранее благодарен.
Сергей.
Re: ADO. Recordset. Повышенный расход памяти.
От: Tom Россия http://www.RSDN.ru
Дата: 07.03.03 09:29
Оценка:
а можно вопрос ?
1. Ты уверен, что под C++ клиентом обьект создаётся под DllHost ? А то вот эта строчка меня пугает:
SP::IFWSetPtr spSet = FWCreateDBSet(testAT); // создается новый экземпляр DBSet-а под dllhost-ом


2. Ты не пробовал воспользоваться BounceChecker ?
... << RSDN@Home 1.0 beta 6a >>
Народная мудрось
всем все никому ничего(с).
Re[2]: ADO. Recordset. Повышенный расход памяти.
От: Кривов Сергей Владимирович Россия  
Дата: 07.03.03 09:42
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>а можно вопрос ?

Tom>1. Ты уверен, что под C++ клиентом обьект создаётся под DllHost ? А то вот эта строчка меня пугает:
Tom>
Tom>SP::IFWSetPtr spSet = FWCreateDBSet(testAT); // создается новый экземпляр DBSet-а под dllhost-ом
Tom>

Уверен абсолютно. FWCreateDBSet — это просто служебная функция которая внутри создает объект на сервере.

Tom>2. Ты не пробовал воспользоваться BounceChecker ?

Пробовал. У меня стоит DevPartnerStudio. Показал нескольо ликов, например — в _bstr_t.Copy(), и еще несколько в системных библиотеках. Ничего близко связанного с моим вопросом не обнаружилось.
Re[3]: ADO. Recordset. Повышенный расход памяти.
От: Tom Россия http://www.RSDN.ru
Дата: 07.03.03 09:49
Оценка:
1. а с чего ты тогда взял, что память утекает ?
2. Приведи всё таки код этой функции (которая создаёт обьект на сервере (dllhost))
... << RSDN@Home 1.0 beta 6a >>
Народная мудрось
всем все никому ничего(с).
Re[4]: ADO. Recordset. Повышенный расход памяти.
От: Кривов Сергей Владимирович Россия  
Дата: 07.03.03 10:02
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>1. а с чего ты тогда взял, что память утекает ?

Поскольку размер используемой памяти dllhost-а увеличивается на 25Мб (видно в TaskManager-е виндов), а если дать не 100 итераций а 150000 то памяти будет уже в районе гига, быстродействие системы падает раз в пять, после чего все умирает.
Tom>2. Приведи всё таки код этой функции (которая создаёт обьект на сервере (dllhost))

SP::IFWDBSetPtr FWCreateDBSet(long attrType,
                              long nStorageID)
{
    SP::IFWDBSetPtr spDBSet=FWGetComponentCreator()->CreateInstance(_CLSID_FWDBSet);
    spDBSet->SetStorageID(nStorageID);
    SP::IFWSetPtr spSet=spDBSet;
    spSet->SetAttrType(attrType);
    return spDBSet;
}

SP::IFWComponentCreatorPtr FWGetComponentCreator()
{
    return FWGetSrvCore()->GetCreator();
}

static CComAutoCriticalSection s_cs;
static StatGIP<IFWSrvCore> s_srvCore;

SP::IFWSrvCorePtr FWGetSrvCore()
{
    CSLocker lck(&s_cs);
    CComPtr<IFWSrvCore> spSrvCore;
    if( !s_srvCore )
    {
        CHECK_HR_ONLY(spSrvCore.CoCreateInstance( _CLSID_FWSrvCore ));
        CHECK_HR_ONLY(s_srvCore.Attach( spSrvCore ));
    }
    if( !spSrvCore )
        CHECK_HR_ONLY(s_srvCore.CopyTo( &spSrvCore ));
    return spSrvCore.p;
}


FWSrvCore — это объект, сконфигурированный в COM+ (собственно dllhost — это COM+ приложение).
FWComponentCreator — Stateless component, предназначенный специально для создания объектов на сервере. Сам создается изнути COM+ приложения (в FWSrvCore).
Re[4]: ADO. Recordset. Повышенный расход памяти.
От: Кривов Сергей Владимирович Россия  
Дата: 07.03.03 10:08
Оценка:
Еще одно уточнение.
Если в тестовой программе убрать вызов GetFirst, где собственно осуществляется открытие ADORecordset-а, с памятью dllhost-а все становится хорошо, ничего не растет.
Я в принципе не могу понять, как ScriptHost может повлиять на размер памяти другого процесса, в то время как аналогичное приложение на C++ этого не делает. Что там, какая-то "интимная" связь между процессом ScriptHost-а и COM+ приложением?
Re[5]: ADO. Recordset. Повышенный расход памяти.
От: Tom Россия http://www.RSDN.ru
Дата: 07.03.03 10:19
Оценка:
не мог бы ты для успокаения моей души взглянуть а не увеличивается ли обьеё памяти при использовании C++ клиента у самого клиента и у COM+ приложения ? И ещё. Что значит фраза

FWSrvCore — это объект, сконфигурированный в COM+ (собственно dllhost — это COM+ приложение).

... << RSDN@Home 1.0 beta 6a >>
Народная мудрось
всем все никому ничего(с).
Re[6]: ADO. Recordset. Повышенный расход памяти.
От: Кривов Сергей Владимирович Россия  
Дата: 07.03.03 10:38
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>не мог бы ты для успокаения моей души взглянуть а не увеличивается ли обьеё памяти при использовании C++ клиента у самого клиента и у COM+ приложения ? И ещё. Что значит фраза

Tom>

Tom>FWSrvCore — это объект, сконфигурированный в COM+ (собственно dllhost — это COM+ приложение).


Объем dllhost-а при использовании С++ клиента увеличивается на 400кб (те же 100 итераций), но через некоторое время уменьшается (видимо освобождается пул коннектов и, возможно COM+ чего нибудь подчищает). Объем самого клиента честно говоря не проверял, и прямо сейчас проверить не смогу — идет повторная перекомпиляция под NuMega. Попробую с ней еще раз погонять.
Насчет COM+ — используется следующая структура. Как COM+ приложение сконфигурированы несколько компонентов (т. е. в COM+-е создано приложение, туда добавлены компоненты (включая FWSrvCore), выставлены нужные атрибуты.) У клиента есть указатель на FWSrvCore — этот объект гарантировано создается в контексте COM+ приложения (т. е. в процессе dllhost-а). Создание любого объекта осуществляется через него.
Первый шаг — у SrvCore запрашивается лекговесный компонент(ComponentCreator) — что-то типа специализированной фабрики классов. Этот компонент не сконфигурирован как COM+ и поэтому создается в контексте несконфигурированных компонентов но в процессе dllhost-а.
Второй шаг — у ComponentCreator-а вызывается метод CreateInstance, который создает нужный нам объект (в данном случае DBSet) опять же в контексте несконфигурированных компонентов но опять же в процессе dllhost-а.
Re[7]: ADO. Recordset. Повышенный расход памяти.
От: Кривов Сергей Владимирович Россия  
Дата: 07.03.03 10:49
Оценка:
КСВ>Здравствуйте, Tom, Вы писали:

Tom>>не мог бы ты для успокаения моей души взглянуть а не увеличивается ли обьеё памяти при использовании C++ клиента у самого клиента и у COM+ приложения ?


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