ImprintEntity - утечка памяти (ObjectArx / C++)
| Правила | Регистрация | Пользователи | Сообщения за день |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > ImprintEntity - утечка памяти (ObjectArx / C++)

ImprintEntity - утечка памяти (ObjectArx / C++)

Ответ
Поиск в этой теме
Непрочитано 17.10.2014, 14:35 #1
ImprintEntity - утечка памяти (ObjectArx / C++)
Glam Troll
 
прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40

При интенсивном использовании (десятки тысяч вызовов подряд) метода AcDb3dSolid::imprintEntity обнаружил огромные утечки памяти. Причём, даже если тела не соприкасаются и в них не происходит никаких изменений. Например, если нарисовать 125 не контактирующих друг с другом кубиков и вызвать импринт для каждой пары из них, то занимаемая память увеличится более чем на 200 мегабайт, хотя абсолютно никакой полезной работы не совершилось. Вызовы acdbAcisDeleteModelerBulletins не только не помогают, но в ObjArx2015 этой функции вовсе нет. (разумеется, imprintEntity вызывается не просто так, а по очень веской причине и в рабочем документе содержится несколько тысяч тел, различным образом контактирующих друг с другом. В реальном документе утечки достигают 10-20 гигабайт и я страдаю).
Может кто-то сталкивался с такой проблемой и знает способы её решения?

P.S. В ADN уже вопрос написал, но мало ли когда они ответят, поэтому надежда на соо вообще и Александра Ривилиса в частности

Вот код примера, если хочется поэкспериментировать с косяком. Если делать imprintEntity не на оригинале, а на временном теле в памяти, то на размере утечек это никак не сказывается.
Код:
[Выделить все]
 
#include "StdAfx.h"
#include "resource.h"
#include <dbacis.h>
#include <vector>

#define OBJECT_ARX_VERSION 20

//-----------------------------------------------------------------------------
#define szRDS _RXST("TEST")

void ImprintAll();

//-----------------------------------------------------------------------------
//----- ObjectARX EntryPoint
class CMiniImpApp : public AcRxArxApp {

public:
	CMiniImpApp () : AcRxArxApp () {}

	virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {
		// TODO: Load dependencies here

		// You *must* call On_kInitAppMsg here
		AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg (pkt) ;

		// TODO: Add your initialization code here

		return (retCode) ;
	}

	virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {
		// TODO: Add your code here

		// You *must* call On_kUnloadAppMsg here
		AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg (pkt) ;

		// TODO: Unload dependencies here

		return (retCode) ;
	}

	virtual void RegisterServerComponents () {
	}


	static void CMiniImpApp_ImprintTest()
	{	ImprintAll();	}

} ;

//-----------------------------------------------------------------------------
IMPLEMENT_ARX_ENTRYPOINT(CMiniImpApp)

ACED_ARXCOMMAND_ENTRY_AUTO( CMiniImpApp, CMiniImpApp, _ImprintTest, ImprintTest, ACRX_CMD_NOINTERNALLOCK | ACRX_CMD_TRANSPARENT | ACRX_CMD_NOHISTORY, NULL );


void ImprintAll()
{
	ads_name ent0, ent1; 

	if( acdbEntNext(NULL, ent0) != RTNORM )
	{ 
		acdbFail(L"Drawing is empty\n"); 
		return; 
	}

	std::vector<AcDbObjectId> allSolids;

	Acad::ErrorStatus err( Acad::eOk );
	do
	{ 
		AcDbObjectId objId;
		err = acdbGetObjectId(objId, ent0);

		AcDbObjectPointer<AcDb3dSolid> object( objId, AcDb::kForRead, FALSE );
		if( object.openStatus() != Acad::eOk )
			continue;

	//	AcDb3dSolid * solid = new AcDb3dSolid;
	//	solid->copyFrom( object );

		allSolids.push_back( objId );

		ads_name_set(ent0, ent1);

	}
	while( acdbEntNext(ent1, ent0) == RTNORM ); 


	for( int i = 0; i < allSolids.size(); ++i )
	{
		AcDbObjectPointer<AcDb3dSolid> solid1( allSolids[i], AcDb::kForWrite, FALSE );

		for( int j = i; j < allSolids.size(); ++j )
		{
			if( i == j )
				continue;

			AcDbObjectPointer<AcDb3dSolid> solid2( allSolids[j], AcDb::kForWrite, FALSE );

			if( Acad::eOk == solid1->imprintEntity( solid2 ) )
			{
				solid2->imprintEntity( solid1 );
			}
		}
	}
}


Последний раз редактировалось Glam Troll, 17.10.2014 в 15:40. Причина: дополнил название темы
Просмотров: 7116
 
Непрочитано 17.10.2014, 15:14
#2
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,411


Glam Troll, ты в заголовке темы укажи - язык, под какую версию пишешь и проч.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 17.10.2014, 15:30
#3
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


ObjectArx, C++
Не могу заголовок исправить...
Glam Troll вне форума  
 
Непрочитано 17.10.2014, 15:32
1 | #4
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,411


Можешь: Как переименовать тему?
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 17.10.2014, 18:38
1 | #5
Do$

AutoCAD/Civil3D LISP/C#
 
Регистрация: 15.08.2008
Санкт-Петербург
Сообщений: 1,701
Отправить сообщение для Do$ с помощью Skype™


Если на C++, да к тому же член ADN, то прямая дорога сюда: http://adn-cis.org/forum/index.php?board=3.0
__________________
Толковый выбор приходит с опытом, а к нему приводит выбор бестолковый. (The Mechanic)
Do$ вне форума  
 
Непрочитано 17.10.2014, 21:02
#6
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,413
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от Glam Troll Посмотреть сообщение
P.S. В ADN уже вопрос написал, но мало ли когда они ответят, поэтому надежда на соо вообще и Александра Ривилиса в частности
Если это баг, то тут я не помогу ничем. Если ты этого не делаешь, то сначала проверяй на пересечение габаритных контейнеров. Если они не пересекаются, то незачем и пытаться пересекать объекты.
P.S.: А с acdbEntNext ты меня пробил на ностальгию. Я эту функцию не использовал лет пятнадцать.
Александр Ривилис вне форума  
 
Автор темы   Непрочитано 20.10.2014, 06:42
#7
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


Цитата:
Сообщение от Александр Ривилис Посмотреть сообщение
сначала проверяй на пересечение габаритных контейнеров
Разумеется габаритные контейнеры проверяю. Тут без проверки, чтобы ошибку явно показать. На каждый импринт "утекает" буквально килобайт памяти, но из-за сложности конструкции накапливаются десятки гигабайт за считанные минуты...
С габаритными контейнерами у автокада тоже баг есть (или фича ). Для некоторых импортированных моделей габаритный контейнер возвращается с учётом координаты 0:0:0. Причём не только методом getextend, но и прям в окне документа если вызвать zoomAll. Причём, только при виде сверху. Стоит повернуть чертёж и нулевая точка не учитывается при вычислении габаритов при зуммировании, но всё-равно учитывается в getextend. Надо про это тоже в АДН написать, хорошо, что напомнили.


Цитата:
Сообщение от Александр Ривилис Посмотреть сообщение
acdbEntNext ты меня пробил на ностальгию. Я эту функцию не использовал лет пятнадцать.
Буду очень благодарен за что-то менее лисповое. Этот код скопипастил у коллег и сделал вид, что так и надо.
Glam Troll вне форума  
 
Непрочитано 20.10.2014, 09:46
#8
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,413
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от Glam Troll Посмотреть сообщение
Буду очень благодарен за что-то менее лисповое. Этот код скопипастил у коллег и сделал вид, что так и надо.
Glam Troll вне форума вставить имя Обратить внимание модератора на это сообщение
Тебя интересуют 3DSolid'ы только в Пространстве Модели или все, которые есть в чертеже, в том числе и лежащие в блоках?
Александр Ривилис вне форума  
 
Автор темы   Непрочитано 20.10.2014, 10:51
#9
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


Интересуют вообще все entity, которые есть в БД документа. Причём, типы некоторых из них мне даже неизвестны (сторонняя библиотека по AcDbObjectId возвращает его солидное представление). В простейшем случае, нужны все солиды и сюрфэйсы с видимых слоёв, включая те, которые в блоках или вставлены по xref.

Кстати! Нынешний код вполне рабочий и его быстродействие меня вполне устраивает. А вот с блоками есть непонятки. К телам в блоках ведь могут применяться различные трансформации и, вытаскивая тело из блока, у меня не всегда эти трансформации удаётся применить. Проблема настолько редкая, что я даже про неё не стал спрашивать в виде отдельной темы. Может сталкивались с подобным?
Glam Troll вне форума  
 
Непрочитано 20.10.2014, 14:39
1 | #10
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,413
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от Glam Troll Посмотреть сообщение
А вот с блоками есть непонятки. К телам в блоках ведь могут применяться различные трансформации и, вытаскивая тело из блока, у меня не всегда эти трансформации удаётся применить. Проблема настолько редкая, что я даже про неё не стал спрашивать в виде отдельной темы.
Ну AutoCAD не идеален...

Цитата:
Сообщение от Glam Troll Посмотреть сообщение
Интересуют вообще все entity, которые есть в БД документа. Причём, типы некоторых из них мне даже неизвестны (сторонняя библиотека по AcDbObjectId возвращает его солидное представление). В простейшем случае, нужны все солиды и сюрфэйсы с видимых слоёв, включая те, которые в блоках или вставлены по xref.
Посмотри. Может из этого кода что-то почерпнёшь:
Код:
[Выделить все]
 static void IterateDatabase () {
   Acad::ErrorStatus es;
   AcDbDatabase *pDb = acdbCurDwg();
   // Метка первого объекта в чертеже
   AcDbHandle firstHandle = pDb->blockTableId().handle();
   // Метка следующего объекта после последнего
   AcDbHandle lastHandle = pDb->handseed();
   int nObjects = pDb->approxNumObjects();
   ACHAR buf1[256],buf2[256];
   firstHandle.getIntoAsciiBuffer(buf1);
   lastHandle.getIntoAsciiBuffer(buf2);
   __int64 iFirst = 0; swscanf(buf1,_T("%I64x"),&iFirst);
   __int64 iLast = 0; swscanf(buf2,_T("%I64x"),&iLast);
   __int64 nTotal = 0;
   acutPrintf(_T("\nПервая метка объекта: <%s>, последняя метка объекта: <%s>"),buf1,buf2);

   for (__int64 i = iFirst; i < iLast && nObjects > 0; i++) {
     AcDbHandle h(i);
     AcDbObjectId id = AcDbObjectId::kNull;
     if ((es = pDb->getAcDbObjectId(id,false,h)) == Acad::eOk) {
       if (id.objectClass()->isDerivedFrom(AcDb3dSolid::desc()) ||
         id.objectClass()->isDerivedFrom(AcDbSurface::desc())) {
           // Нашли 3DSolid или Surface
           // AcDbEntityPointer pObj(id,AcDb::kForRead);
           // if (pObj.openStatus() == Acad::eOk) {
           //   // Печатаем информацию о нём
           //   pObj->list();
           // }
           nTotal++;
       }
     }
   }
   wsprintf(buf1,_T("\nВсего найдено твердых тел и поверхностей %I64d."),nTotal); 
   acutPrintf(_T("%s"),buf1);
}
Александр Ривилис вне форума  
 
Автор темы   Непрочитано 20.10.2014, 15:09
#11
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


Цитата:
Сообщение от Александр Ривилис Посмотреть сообщение
Может из этого кода что-то почерпнёшь
Благодарю!
А непосредственно по AcDbHandle итерировать не пробовали? Для них ведь и оператор < и != определён. Судя по "AcDbHandle h(i);" это будет одно и то же.
Glam Troll вне форума  
 
Непрочитано 20.10.2014, 16:05
#12
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,413
Отправить сообщение для Александр Ривилис с помощью Skype™


Цитата:
Сообщение от Glam Troll Посмотреть сообщение
А непосредственно по AcDbHandle итерировать не пробовали? Для них ведь и оператор < и != определён. Судя по "AcDbHandle h(i);" это будет одно и то же.
Перечитай,только внимательно мой код и обрати внимание на pDb->getAcDbObjectId(id,false,h)) - без него ты можешь получить несуществующий в даном чертеже AcDbHandle
Александр Ривилис вне форума  
 
Автор темы   Непрочитано 20.10.2014, 16:13
#13
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


Цитата:
Сообщение от Александр Ривилис Посмотреть сообщение
pDb->getAcDbObjectId(id,false,h))
Действительно, не обратил внимания. С учётом огромного количества объектов в документе (там ещё и текст и 2Д построения и куча прочего мусора) и их создания/удаления код выглядит как-то опасно. В принципе, инвалидный объект всё-равно не откроется. А вот что может потребоваться тысячи идентификаторов уже "удалённых" объектов отсеивать... Думаю, автокад делает примерно то же самое в методе acdbEntNext, пропуская идентификаторы удалённых объектов.
Glam Troll вне форума  
 
Непрочитано 20.10.2014, 16:30
1 | #14
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,413
Отправить сообщение для Александр Ривилис с помощью Skype™


Можешь из спортивного интереса засечь скорость работы обоих методов. Достоинство моего метода в том, что можно работать и с чертежами, которые не загружены в редактор AutoCAD (т.е. открыты через AcDbDatabase::readDwgFile) или не являются активными в редакторе AutoCAD. Функция acedEntNext работает только с активным dwg-файлом.
Александр Ривилис вне форума  
 
Автор темы   Непрочитано 20.10.2014, 16:41
#15
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


Цитата:
Сообщение от Александр Ривилис Посмотреть сообщение
можно работать и с чертежами, которые не загружены в редактор AutoCAD
А вот это круто! У меня есть пакетная работа с файлами, этот способ может пригодиться. У меня сейчас через именованную таблицу данные находятся, может что-нибудь оптимизировать получится.
Glam Troll вне форума  
 
Непрочитано 20.10.2014, 19:20
1 | #16
Александр Ривилис

программист, рыцарь ObjectARX
 
Регистрация: 09.05.2005
Киев
Сообщений: 2,413
Отправить сообщение для Александр Ривилис с помощью Skype™


В дальнейшем, пожалуйста, посмотри в мою подпись и можешь задавать вопросы там. Во всяком случае специалистов по ObjectARX там больше и легче программистским коллективом "давить на Autodesk".
Александр Ривилис вне форума  
 
Непрочитано 26.10.2014, 02:54
#17
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Цитата:
Сообщение от Glam Troll Посмотреть сообщение
При интенсивном использовании (десятки тысяч вызовов подряд) метода AcDb3dSolid::imprintEntity
А в чем причина такого частого вызова (видимо идет сравнение "каждый к каждому") - какова конечная цель? Быть может возможно будет придумать оптимизацию.
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Автор темы   Непрочитано 26.10.2014, 06:32
#18
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


Цитата:
Сообщение от Дима_ Посмотреть сообщение
А в чем причина такого частого вызова
В реальной программе imprint делается только для тех тел, чьи габаритные контейнеры пересекаются (но это всё-равно тысячи вызовов). По этим телам строится КЭ сетка и сеточному генератору необходимо, чтобы в зоне контакта сетки совпадали. Обеспечить это можно только проецированием тел друг на друга. Если с плоскими гранями ещё можно что-то придумать, дробить самостоятельно сетку, после получения её из BREP'a, то вот с не плоскими поверхностями выбора никакого нет. BREP аппроксимирует кривые так, как ему приспичит и состыковать тела просто невозможно без imprint'a.
Glam Troll вне форума  
 
Непрочитано 26.10.2014, 13:18
#19
Дима_

Продуман
 
Регистрация: 22.02.2007
Питер
Сообщений: 2,839


Цитата:
Сообщение от Glam Troll Посмотреть сообщение
По этим телам строится КЭ сетка и сеточному генератору необходимо, чтобы в зоне контакта сетки совпадали.
Вот эту часть можно поподробней -оперируя только автокадными понятиями.
__________________
Когда в руках молоток все вокруг кажется гвоздями.
Дима_ вне форума  
 
Автор темы   Непрочитано 26.10.2014, 14:12
#20
Glam Troll

прохраммист ObjectArx
 
Регистрация: 01.11.2010
Сообщений: 40


Цитата:
Сообщение от Дима_ Посмотреть сообщение
оперируя только автокадными понятиями
Автокадными понятиями это не объяснить, потому что к автокаду отношения в принципе не имеет.) Если попытаться... То при использовании BREP, контактирующие грани должны совпадать.
Glam Troll вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > ImprintEntity - утечка памяти (ObjectArx / C++)



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
как бороться с ошибкой выделения памяти ratkill SCAD 14 07.09.2015 16:20
VBA: утечка памяти при вставке блоков Mikha Программирование 13 03.04.2009 09:18
При запуске Lisp идет утечка памяти Name LISP 6 24.07.2007 14:36
Утечка памяти mental Программирование 2 22.02.2007 07:40
Лира 9.2 + 1 Гб оперативной памяти nikе Лира / Лира-САПР 3 28.01.2006 19:02