Plug memory leak in register code

The table storing cell dimensions was never freed. The size of this table is
directly proportional to the number of cells in the register. So the more
transactions/splits in a register, the more memory was leaked - each time
a register was opened and closed. With my huge test book I saw leaks of
4Mb-10Mb per page that was opened/closed.
This commit is contained in:
Geert Janssens 2018-09-09 12:35:56 +02:00
parent 4cc61463ab
commit 3845611f30
4 changed files with 39 additions and 23 deletions

View File

@ -159,7 +159,6 @@ void gnc_split_reg_sort_action_cb (GtkWidget *w, gpointer data);
void gnc_split_reg_sort_notes_cb (GtkWidget *w, gpointer data);
void gnc_split_reg_destroy_cb(GtkWidget *widget, gpointer data);
void gnc_split_reg_size_allocate( GtkWidget *widget,
GtkAllocation *allocation,
gpointer user_data );
@ -168,6 +167,7 @@ void gnc_split_reg_size_allocate( GtkWidget *widget,
static void gnc_split_reg_class_init( GNCSplitRegClass *klass );
static void gnc_split_reg_init( GNCSplitReg *gsr );
static void gnc_split_reg_init2( GNCSplitReg *gsr );
void gnc_split_reg_dispose(GObject *obj);
FROM_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
AS_STRING_FUNC(SortType, ENUM_LIST_SORTTYPE)
@ -314,6 +314,8 @@ gnc_split_reg_class_init( GNCSplitRegClass *klass )
klass->help_changed_cb = NULL;
klass->show_popup_menu_cb = NULL;
klass->include_date_cb = NULL;
object_class->dispose = gnc_split_reg_dispose;
}
GtkWidget*
@ -354,9 +356,6 @@ gnc_split_reg_init( GNCSplitReg *gsr )
gsr->height = -1;
gsr->numRows = 10;
gsr->read_only = FALSE;
g_signal_connect( gsr, "destroy",
G_CALLBACK (gnc_split_reg_destroy_cb), gsr );
}
static void
@ -444,12 +443,18 @@ gsr_setup_status_widgets( GNCSplitReg *gsr )
}
void
gnc_split_reg_destroy_cb(GtkWidget *widget, gpointer data)
gnc_split_reg_dispose(GObject *obj)
{
GNCSplitReg *gsr = data;
GNCSplitReg *gsr = GNC_SPLIT_REG(obj);
if (gsr->filter_text)
g_free (gsr->filter_text);
gsr->filter_text = NULL;
if (gsr->reg)
g_signal_handlers_disconnect_by_data (gsr->reg, gsr);
gtk_widget_destroy (GTK_WIDGET (gsr->reg));
gsr->reg = NULL;
}
/**
@ -710,7 +715,9 @@ gnc_split_reg_ld_destroy( GNCLedgerDisplay *ledger )
}
g_free (state_section);
g_free (acct_fullname);
gnc_ledger_display_set_user_data (ledger, NULL);
g_object_unref (gsr);
}
void

View File

@ -763,6 +763,7 @@ gnucash_sheet_finalize (GObject *object)
sheet = GNUCASH_SHEET (object);
g_table_resize (sheet->blocks, 0, 0);
g_table_destroy (sheet->blocks);
sheet->blocks = NULL;
@ -2214,7 +2215,7 @@ gnucash_sheet_block_set_from_table (GnucashSheet *sheet,
if (block->style && (block->style != style))
{
gnucash_style_unref (block->style);
gnucash_sheet_style_unref (sheet, block->style);
block->style = NULL;
}
@ -2223,7 +2224,7 @@ gnucash_sheet_block_set_from_table (GnucashSheet *sheet,
if (block->style == NULL)
{
block->style = style;
gnucash_style_ref(block->style);
gnucash_sheet_style_ref(sheet, block->style);
return TRUE;
}
@ -2323,14 +2324,15 @@ static void
gnucash_sheet_block_destroy (gpointer _block, gpointer user_data)
{
SheetBlock *block = _block;
GnucashSheet *sheet = GNUCASH_SHEET(user_data);
if (block == NULL)
return;
if (block->style)
{
gnucash_style_unref (block->style);
block->style = NULL;
gnucash_sheet_style_unref (sheet, block->style);
/* Don't free the block itself here. It's managed by the block table */
}
}
@ -2588,7 +2590,7 @@ gnucash_sheet_init (GnucashSheet *sheet)
sheet->blocks = g_table_new (sizeof (SheetBlock),
gnucash_sheet_block_construct,
gnucash_sheet_block_destroy, NULL);
gnucash_sheet_block_destroy, sheet);
gtk_widget_add_events(GTK_WIDGET(sheet), (GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
@ -2723,7 +2725,7 @@ gnucash_sheet_new (Table *table)
/* some register data */
sheet->dimensions_hash_table = g_hash_table_new_full (g_int_hash,
g_int_equal,
g_free, NULL);
g_free, g_free);
/* add tooltips to sheet */
gtk_widget_set_has_tooltip (GTK_WIDGET(sheet), TRUE);

View File

@ -99,10 +99,15 @@ style_dimensions_destroy (BlockDimensions *dimensions)
if (dimensions == NULL)
return;
g_table_destroy (dimensions->cell_dimensions);
dimensions->cell_dimensions = NULL;
dimensions->refcount--;
g_free(dimensions);
if (dimensions->refcount == 0)
{
g_table_destroy (dimensions->cell_dimensions);
dimensions->cell_dimensions = NULL;
g_free(dimensions);
}
}
@ -644,7 +649,7 @@ destroy_style_helper (gpointer key, gpointer value, gpointer user_data)
SheetBlockStyle *style = value;
GnucashSheet *sheet = user_data;
gnucash_sheet_style_destroy (sheet, style);
gnucash_sheet_style_unref (sheet, style);
g_free (cursor_name);
}
@ -674,10 +679,12 @@ gnucash_sheet_create_styles (GnucashSheet *sheet)
for (node = cursors; node; node = node->next)
{
CellBlock *cursor = node->data;
SheetBlockStyle *style = gnucash_sheet_style_new (sheet, cursor);
gnucash_sheet_style_ref (sheet, style);
g_hash_table_insert (sheet->cursor_styles,
g_strdup (cursor->cursor_name),
gnucash_sheet_style_new (sheet, cursor));
style);
}
}
@ -798,7 +805,7 @@ gnucash_sheet_get_style_from_cursor (GnucashSheet *sheet,
*/
void
gnucash_style_ref (SheetBlockStyle *style)
gnucash_sheet_style_ref (GnucashSheet *sheet, SheetBlockStyle *style)
{
g_return_if_fail (style != NULL);
@ -807,14 +814,14 @@ gnucash_style_ref (SheetBlockStyle *style)
void
gnucash_style_unref (SheetBlockStyle *style)
gnucash_sheet_style_unref (GnucashSheet *sheet, SheetBlockStyle *style)
{
g_return_if_fail (style != NULL);
style->refcount--;
if (style->refcount < 0)
g_warning ("Unbalanced Style ref/unref");
if (style->refcount == 0)
gnucash_sheet_style_destroy (sheet, style);
}
typedef struct

View File

@ -109,8 +109,8 @@ void gnucash_sheet_style_get_cell_pixel_rel_coords (SheetBlockStyle *style,
gint *x, gint *y,
gint *w, gint *h);
void gnucash_style_ref (SheetBlockStyle *style);
void gnucash_style_unref (SheetBlockStyle *style);
void gnucash_sheet_style_ref (GnucashSheet *sheet, SheetBlockStyle *style);
void gnucash_sheet_style_unref (GnucashSheet *sheet, SheetBlockStyle *style);
void gnucash_sheet_get_borders (GnucashSheet *sheet, VirtualLocation virt_loc,
PhysicalCellBorders *borders);