Serg-Norseman / GEDKeeper

GEDKeeper - program for work with personal genealogical database
https://gedkeeper.net/
GNU General Public License v3.0
149 stars 44 forks source link

Potential Memory Leak #535

Open fullben opened 4 months ago

fullben commented 4 months ago

Environment

Observed Behavior

I have a nearly blank .ged file that I start out with. In the primary people tab, I start adding new people records. These records usually contain no information besides the persons' names, birth/death date and location, marriage information... I have not added any media or image data to the file.

Every time I complete the input for a person's data in the popup and return to the main window, the main window will freeze. This behavior is observable even after having modified only a small number of records. The duration of the freeze increases over time and seems to be related to the number of modifications made in the popup windows. Memory usage also increases significantly over time.

Restarting the application usually "fixes" the issue in the sense that a few modifications work with little to no noticeable freezes before the freezes become noticeable again.

The following table gives a rough idea of the behavior I'm observing.

Up Time Memory Usage Freeze on Return to Main Window
0mins 210MB 0-2 seconds
15mins 460MB 2-5 seconds
30mins 640MB 5-15 seconds

If left idle, the application's memory usage remains constant.

On a previous run, I created a new file, added about 30-50 people and then had the app freeze (at the point in the workflow described above), before it finally crashed on me. During that run, the following error output appeared in the application log:

[2/11/2024 16:36:06] [ERROR] -> GKListView.SelectItem(): Exception of type 'System.OutOfMemoryException' was thrown.
    Exception data:
    StackTrace:
       at MS.Internal.Xaml.Context.ObjectWriterContext..ctor(XamlSavedContext savedContext, XamlObjectWriterSettings settings, INameScope rootNameScope, XamlRuntime runtime)
           at System.Xaml.XamlObjectWriter.Initialize(XamlSchemaContext schemaContext, XamlSavedContext savedContext, XamlObjectWriterSettings settings)
           at System.Xaml.XamlObjectWriter..ctor(XamlSavedContext savedContext, XamlObjectWriterSettings settings)
           at MS.Internal.Xaml.Context.XamlObjectWriterFactory.GetXamlObjectWriter(XamlObjectWriterSettings settings)
           at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)
           at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren)
           at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
           at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
           at System.Windows.FrameworkElement.ApplyTemplate()
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.Controls.DataGridCellsPanel.MeasureChild(UIElement child, Size constraint)
           at System.Windows.Controls.DataGridCellsPanel.GenerateChildren(IItemContainerGenerator generator, Int32 startIndex, Int32 endIndex, Size constraint)
           at System.Windows.Controls.DataGridCellsPanel.GenerateAndMeasureChildrenForRealizedColumns(Size constraint)
           at System.Windows.Controls.DataGridCellsPanel.MeasureOverride(Size constraint)
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.Controls.ItemsPresenter.MeasureOverride(Size constraint)
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.Controls.Control.MeasureOverride(Size constraint)
           at System.Windows.Controls.Primitives.DataGridCellsPresenter.MeasureOverride(Size availableSize)
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
           at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
           at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.Controls.Border.MeasureOverride(Size constraint)
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.Controls.Control.MeasureOverride(Size constraint)
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.Controls.VirtualizingStackPanel.MeasureChild(IItemContainerGenerator& generator, IContainItemStorage& itemStorageProvider, IContainItemStorage& parentItemStorageProvider, Object& parentItem, Boolean& hasUniformOrAverageContainerSizeBeenSet, Double& computedUniformOrAverageContainerSize, Double& computedUniformOrAverageContainerPixelSize, Boolean& computedAreContainersUniformlySized, Boolean& hasAnyContainerSpanChanged, IList& items, Object& item, IList& children, Int32& childIndex, Boolean& visualOrderChanged, Boolean& isHorizontal, Size& childConstraint, Rect& viewport, VirtualizationCacheLength& cacheSize, VirtualizationCacheLengthUnit& cacheUnit, Int64& scrollGeneration, Boolean& foundFirstItemInViewport, Double& firstItemInViewportOffset, Size& stackPixelSize, Size& stackPixelSizeInViewport, Size& stackPixelSizeInCacheBeforeViewport, Size& stackPixelSizeInCacheAfterViewport, Size& stackLogicalSize, Size& stackLogicalSizeInViewport, Size& stackLogicalSizeInCacheBeforeViewport, Size& stackLogicalSizeInCacheAfterViewport, Boolean& mustDisableVirtualization, Boolean isBeforeFirstItem, Boolean isAfterFirstItem, Boolean isAfterLastItem, Boolean skipActualMeasure, Boolean skipGeneration, Boolean& hasBringIntoViewContainerBeenMeasured, Boolean& hasVirtualizingChildren)
           at System.Windows.Controls.VirtualizingStackPanel.MeasureOverrideImpl(Size constraint, Nullable`1& lastPageSafeOffset, List`1& previouslyMeasuredOffsets, Nullable`1& lastPagePixelSize, Boolean remeasure)
           at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint)
           at System.Windows.Controls.Primitives.DataGridRowsPresenter.MeasureOverride(Size constraint)
           at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
           at System.Windows.UIElement.Measure(Size availableSize)
           at System.Windows.ContextLayoutManager.UpdateLayout()
           at System.Windows.UIElement.UpdateLayout()
           at System.Windows.Controls.ItemsControl.OnBringItemIntoView(ItemInfo info)
           at System.Windows.Controls.DataGrid.ScrollIntoView(ItemInfo info)
           at System.Windows.Controls.DataGrid.ScrollIntoView(Object item)
           at Eto.Wpf.Forms.Controls.GridHandler`2.ScrollToRow(Int32 row)
           at GKUI.Components.GKListView.SelectItem(Int32 index)
           at GKUI.Components.GKListView.SelectItem(Object rowData)

Disclaimer

I'm new to the field of genealogy, maybe I'm doing something wrong when entering my data.

Serg-Norseman commented 4 months ago

Thank you! I'll see what I can do

esd3v commented 4 months ago

Same for portable version

burtek commented 4 months ago

I've also seen this happenning. When I work a lot with GEDKeeper, my RAM starts slowly filling up and only empties when I close/restart GEDKeeper. After restarting and reopening the gedcom file, it doesn't use as much memory as before closing.

Was actually planning on reporting this myself soon

burtek commented 4 months ago

I'm not familiar with C# so idk if it's a thing, but in C++, whenever I create/allocate memory using type* x = new X syntax, I have to manually release that memory using delete x. Maybe that's the issue here? In last commit there are few examples of using new string[N] or new List, but they are never deleted... Again, not familiar with C#, just trying to help a bit

Serg-Norseman commented 4 months ago

Managed objects (string, List, etc) are freed automatically by the garbage collector when they go out of scope

Serg-Norseman commented 4 months ago

There is a deeper problem, it may or may not be in my code, but definitely somewhere at the junction with the Eto.Forms framework and between it and WPF. The profiler detects severe memory loss in a number of areas, but cannot determine the exact location.

Serg-Norseman commented 4 months ago

I keep looking. I won't close this issue for now