Hi, I am trying write AnnotationFeatureClasses to a file geodatabase. When I write to the FGDB the first time it works ok. Lockfiles are created, but they are never deleted. The VisualStudio Debug-Console puts out the following line when I start to debug:
BGLEngine 0000023DA00ABB70 was created (from the thread id: 3136).
What should happen after all writes are done is that the Debug-Console prints the next line:
BGLEngine 0000023DA00ABB70 was destroyed (from the thread id: 3136).
and the lock on the FGDB should have been removed.
However, the Lock never gets released and I will be unable to write a second time to the FGDB. When I stop the application the debug-console prints:
CIM.DLL Terminating!
Starting BGLEngine leak diagnostics...
*****************************************************
Check for unreleased BGL classes.
BGLCanvas: 1 objects leaked
BGLPath: 1 objects leaked
BGLEngine: 1 object leaked
All references to this Engine's BGL objects become invalid now.
*****************************************************
BGLEngine 0000023DA00ABB70 (from the thread id: 3136) is not released before unloading of the BGLAPI.dll.
BGLEngine leak diagnostics completed.
From what I understand is that I have to call Dispose() on every ArcGIS-Object related to databases. I am not sure where I might have left any reference to the ArcGIS code dangling. From the BGLEngine leak diagnostics I am geussing that there might be something wrong with the CIMLabelClasses, but those cannot be disposed. The only places where Dispose() must be called is where I interact with a DataBase.
Solved! Go to Solution.
Thanks for the thorough explanation, @Meroni ! We can reproduce the BGLEngine leak, the dev team will investigate and update the thread.
4. Press the close button of the console window (important, red cross in the right upper corner, NOT the stop debugging button in VS. Lock-Files wouldn't disapear unless I would close our application).
FeatureDataset.Dispose () is removing the lock in our case, and also recommends to dispose the feature dataset definition.
Hi @Aashis, I have solved my problem while I was writing a minimal example to reproduce the BGLEnginerelated error. What our application does at some point is calling a FeatureClassBuilder which either uses the method CreateFeatureClass() or CreateAnnotationFeatureClass(). Those two methods are very simliar except for the fact that one uses a FeatureClassDescription and the other one an AnnotationFeatureClasseDescription for the SchemaBuilder.
The method CreateFeatureClass looks something like this
public void CreateFeatureClass(){
...
...
...
var featureDataset = FGDB.OpenDataset<FeatureDataset>("Points");
...
...
...
SchemaBuilder schemaBuilder = new SchemaBuilder(FGDB);
schemaBuilder.Create(new FeatureDatasetDescription(featureDataset.GetDefinition()), featureClassDescription);
bool success = schemaBuilder.Build();
...
...
...
}
and the method shown above works fine. All locks are removed after FGBD.Dispose() is called and the FGDB can be written to again. While the above works fine for normal FeatureClasses it won't for AnnotationFeatureClasses. I had to call featureDataset.Dispose() after schemaBuilder.Build() was done. Initially I copied CreateFeatureClass() to CreateAnnotationFeatureClass() and thats why it slipped passed me to dispose featureDataset (like shown below).
public void CreateAnnotationFeatureClass(){
...
...
...
var featureDataset = FGDB.OpenDataset<FeatureDataset>("Points");
...
...
...
SchemaBuilder schemaBuilder = new SchemaBuilder(FGDB);
schemaBuilder.Create(new FeatureDatasetDescription(featureDataset.GetDefinition()), annotationFeatureClassDescription);
bool success = schemaBuilder.Build();
featureDataset.Dispose();
...
...
...
}
However, why does this only breack when calling SchemaBuilder.Create() on a featureDataset-definition of an AnnotationFeature-Dataset and not when a Feature-Dataset is used? I understand that the BGLEngine gets only instantiated when I try to create AnnotationFeatureClasses, because it handles CIM. Do the locks persist because the thread can not be closed from where the BGLEngine was originally created (since the BGLEngine never gets destroyed)? If so, what happens to a dangling featureDataset of standard "Feature"? Because a dangling FeatureDataset does not seem to breack anything as long as anything related to CIM is not involved.
@Meroni We still could not reproduce it on our machine. The lock disappears as soon as the debugger steps out of the geodatabase scope and can add more feature classes and annotation feature classes with no issues. Here is the code snippet that I have tried in Pro SDK 3.0.3. Could you please try?
static void Main(string[] args)
{
//Call Host.Initialize before constructing any objects from ArcGIS.Core
Host.Initialize();
//TODO: Add your business logic here.
string gdbPath = Path.GetTempPath() + "\\MySample.gdb";
InitialBuilder(gdbPath);
AddMore(gdbPath);
}
private static void InitialBuilder(string gdbPath)
{
try
{
using (Geodatabase geodatabase = SchemaBuilder.CreateGeodatabase(new FileGeodatabaseConnectionPath(new Uri(gdbPath))))
{
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
FeatureDatasetDescription featureDatasetDescription = new FeatureDatasetDescription("MyFeatureDataset", SpatialReferences.WGS84);
FeatureDatasetToken featureDatasetToken = schemaBuilder.Create(featureDatasetDescription);
// Feature class
FeatureClassDescription featureClassDescription = new FeatureClassDescription("MyFeatureClass", new List<FieldDescription>(), new ShapeDescription(GeometryType.Polygon, SpatialReferences.WGS84));
FeatureClassToken featureClasToken = schemaBuilder.Create(new FeatureDatasetDescription(featureDatasetToken), featureClassDescription);
// Annotation feature class
AnnotationFeatureClassDescription annotationFeatureClassDescription = new AnnotationFeatureClassDescription("MyAnnotationClass", new List<FieldDescription>(), new ShapeDescription(GeometryType.Polygon, SpatialReferences.WGS84), GetGeneralPlacementProperties(), new List<CIMLabelClass>() { GetRedLabelClass() });
AnnotationFeatureClassToken annotationClassToken = schemaBuilder.Create(new FeatureDatasetDescription(featureDatasetToken), annotationFeatureClassDescription);
bool isSuccess = schemaBuilder.Build();
if (!isSuccess)
{
Console.WriteLine(schemaBuilder.ErrorMessages.FirstOrDefault());
}
using (FeatureDataset featureDataset = geodatabase.OpenDataset<FeatureDataset>("MyFeatureDataset"))
{
string featureDatasetPath = featureDataset.GetPath().AbsolutePath;
Console.WriteLine(featureDatasetPath);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AddMore(string gdbPath)
{
try
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(gdbPath))))
{
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
using (FeatureDataset featureDataset = geodatabase.OpenDataset<FeatureDataset>("MyFeatureDataset"))
using (FeatureDatasetDefinition featureDatasetDefinition = featureDataset.GetDefinition())
{
FeatureDatasetDescription featureDatasetDescription = new FeatureDatasetDescription(featureDatasetDefinition);
// Feature class
FeatureClassDescription featureClassDescription = new FeatureClassDescription("MyFeatureClass1", new List<FieldDescription>(), new ShapeDescription(GeometryType.Polygon, SpatialReferences.WGS84));
FeatureClassToken featureClasToken = schemaBuilder.Create(featureDatasetDescription, featureClassDescription);
// Annotation feature class
AnnotationFeatureClassDescription annotationFeatureClassDescription = new AnnotationFeatureClassDescription("MyAnnotationClass1", new List<FieldDescription>(), new ShapeDescription(GeometryType.Polygon, SpatialReferences.WGS84), GetGeneralPlacementProperties(), new List<CIMLabelClass>() { GetRedLabelClass() });
AnnotationFeatureClassToken annotationClassToken = schemaBuilder.Create(featureDatasetDescription, annotationFeatureClassDescription);
bool isSuccess = schemaBuilder.Build();
if (!isSuccess)
{
Console.WriteLine(schemaBuilder.ErrorMessages.FirstOrDefault());
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
SchemaBuilder.DeleteGeodatabase(new FileGeodatabaseConnectionPath(new Uri(gdbPath)));
}
}
private static CIMGeneralPlacementProperties GetGeneralPlacementProperties()
{
CIMMaplexGeneralPlacementProperties maplexCimGeneralPlacementProperties =
new CIMMaplexGeneralPlacementProperties
{
AllowBorderOverlap = true,
PlacementQuality = MaplexQualityType.High,
DrawUnplacedLabels = true,
InvertedLabelTolerance = 1.0,
RotateLabelWithDisplay = true,
UnplacedLabelColor = new CIMRGBColor { R = 0, G = 255, B = 0, Alpha = 0.5f } // Green
};
return maplexCimGeneralPlacementProperties;
}
private static CIMLabelClass GetRedLabelClass()
{
CIMLabelClass redLabelClass = new CIMLabelClass
{
Name = "Red",
ExpressionTitle = "Expression-Red",
ExpressionEngine = LabelExpressionEngine.Arcade,
Expression = "$feature.OBJECTID",
ID = 0,
Priority = 0,
Visibility = true,
TextSymbol = new CIMSymbolReference
{
Symbol = new CIMTextSymbol()
{
Angle = 45,
FontType = FontType.Type1,
FontFamilyName = "Arial",
FontEffects = FontEffects.Normal,
HaloSize = 2.0,
Symbol = new CIMPolygonSymbol { SymbolLayers = new CIMSymbolLayer[] { new CIMSolidFill() { Color = CIMColor.CreateRGBColor(255, 0, 0) } }, UseRealWorldSymbolSizes = true }
},
MaxScale = 0,
MinScale = 0,
SymbolName = "TextSymbol-RED"
},
StandardLabelPlacementProperties = new CIMStandardLabelPlacementProperties
{
AllowOverlappingLabels = true,
LineOffset = 1.0
},
MaplexLabelPlacementProperties = new CIMMaplexLabelPlacementProperties
{
AlignLabelToLineDirection = true,
AvoidPolygonHoles = true
}
};
return redLabelClass;
}
@Aashis I have complied script which should reproduce the error message.
Steps to reproduce:
1. Make sure that the native debugging option in VS is aktive (mixed-mode debugging).
2. Have a File-GDB with at least one Feature-Dataset (in my case the Feature-Dataset was called "Punkte").
3. Start debugging and wait for the program to get caught in the infinite-loop (simulating our application which runs after the write to the FGDB is complete).
4. Press the close button of the console window (important, red cross in the right upper corner, NOT the stop debugging button in VS. Lock-Files wouldn't disapear unless I would close our application).
5. If the dubugger stops at a breakpoint after the close button was pressed, resume by pressing F5 or the resume button in VS. Otherwise the debugger stops automatically at some point and the BGL diagnostics message won't be printed to the debug console of VS.
At the end this should be printed in output:
CIM.DLL Terminating!
Starting BGLEngine leak diagnostics...
*****************************************************
Check for unreleased BGL classes.
BGLCanvas: 1 objects leaked
BGLPath: 1 objects leaked
BGLEngine: 1 object leaked
All references to this Engine's BGL objects become invalid now.
*****************************************************
BGLEngine 000001FF7A2944E0 (from the thread id: 28360) is not released before unloading of the BGLAPI.dll.
BGLEngine leak diagnostics completed.
CIMLib.dll Terminating!
class Program {
//[STAThread] must be present on the Application entry point
[STAThread]
static void Main(string[] args)
{
//Call Host.Initialize before constructing any objects from ArcGIS.Core
try
{
//ArcGIS.Core.Hosting.Host.Initialize();
PerformCoreHostTask(args);
}
catch (Exception e)
{
// Error (missing installation, no license, 64 bit mismatch, etc.)
Console.WriteLine(string.Format("Initialization failed: {0}", e.Message));
return;
}
}
private static void PerformCoreHostTask(string[] args)
{
Host.Initialize();
//if (args.Count() > 0) gdbPath = args[0];
var gdbPath = @"C:\Temp\bglenginetest.gdb";// args[0];
try
{
var fgdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(gdbPath, UriKind.Absolute)));
Console.WriteLine("Add Annotation-FeatureClass...");
CreatingAnAnnotationFeature(fgdb);
fgdb.Dispose();
while (true)
Console.WriteLine("Application processes...");
}
catch (Exception e)
{
Console.WriteLine(string.Format("Cannot read file Geodatabase [{0}] error: {1}", gdbPath, e.Message));
return;
}
}
public static void CreatingAnAnnotationFeature(Geodatabase geodatabase)
{
string annotationFeatureClassName = "CitiesAnnotation" + Guid.NewGuid().ToString("N");
FieldDescription globalIDFieldDescription = FieldDescription.CreateGlobalIDField();
FieldDescription nameFieldDescription = FieldDescription.CreateStringField("Name", 255);
List<FieldDescription> fieldDescriptions = new List<FieldDescription> { globalIDFieldDescription, nameFieldDescription };
var spatRef = SpatialReferenceBuilder.CreateSpatialReference(25832);
ShapeDescription shapeDescription = new ShapeDescription(GeometryType.Polygon, spatRef);
CIMMaplexGeneralPlacementProperties generalPlacementProperties =
new CIMMaplexGeneralPlacementProperties
{
AllowBorderOverlap = true,
PlacementQuality = MaplexQualityType.High,
DrawUnplacedLabels = true,
InvertedLabelTolerance = 1.0,
RotateLabelWithDisplay = true,
UnplacedLabelColor = new CIMRGBColor
{
R = 0,
G = 255,
B = 0,
Alpha = 0.5f // Green
}
};
CIMLabelClass greenLabelClass = new CIMLabelClass
{
Name = "Green",
ExpressionTitle = "Expression-Green",
ExpressionEngine = LabelExpressionEngine.Arcade,
Expression = "$feature.OBJECTID",
ID = 1,
Priority = 0,
Visibility = true,
TextSymbol = new CIMSymbolReference
{
Symbol = new CIMTextSymbol()
{
Angle = 45,
FontType = FontType.Type1,
FontFamilyName = "Tahoma",
FontEffects = FontEffects.Normal,
HaloSize = 2.0,
Symbol = new CIMPolygonSymbol
{
SymbolLayers = new CIMSymbolLayer[]
{
new CIMSolidFill
{
Color = CIMColor.CreateRGBColor(0, 255, 0)
}
},
UseRealWorldSymbolSizes = true
}
},
MaxScale = 0,
MinScale = 0,
SymbolName = "TextSymbol-Green"
},
StandardLabelPlacementProperties = new CIMStandardLabelPlacementProperties
{
AllowOverlappingLabels = true,
LineOffset = 1.0
},
MaplexLabelPlacementProperties = new CIMMaplexLabelPlacementProperties
{
AlignLabelToLineDirection = true,
AvoidPolygonHoles = true
}
};
List<CIMLabelClass> labelClasses = new List<CIMLabelClass> { greenLabelClass};
AnnotationFeatureClassDescription annotationFeatureClassDescription =
new AnnotationFeatureClassDescription(annotationFeatureClassName, fieldDescriptions, shapeDescription,
generalPlacementProperties, labelClasses)
{
IsAutoCreate = true,
IsSymbolIDRequired = false,
IsUpdatedOnShapeChange = true
};
//----------------------------------
#region FeatureDatasetRegion
FeatureDataset featureDataset = geodatabase.OpenDataset<FeatureDataset>("Punkte");
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Create(new FeatureDatasetDescription(featureDataset.GetDefinition()), annotationFeatureClassDescription);
bool success = schemaBuilder.Build();
// But not calling Dispoe()!
//featureDataset.Dispose();
#endregion
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
foreach (var message in errorMessages)
{
Console.WriteLine(message);
}
}
}
}
Thanks for the thorough explanation, @Meroni ! We can reproduce the BGLEngine leak, the dev team will investigate and update the thread.
4. Press the close button of the console window (important, red cross in the right upper corner, NOT the stop debugging button in VS. Lock-Files wouldn't disapear unless I would close our application).
FeatureDataset.Dispose () is removing the lock in our case, and also recommends to dispose the feature dataset definition.
@Aashis one last thing. Through the entire debug process I wished for a way to see which objects still need disposing. This is probably not the right place for a feature request, but it would have been nice if I could print out all objects which still need disposing or a method which simply disposes everything at once if I can't find the undisposed object.
This said, before this goes offtopic I am going to accept your reply and mark this question as done.