diff --git a/src/ring.c b/src/ring.c
index 3d485e7..9f03ff0 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -73,6 +73,8 @@ _vte_ring_init (VteRing *ring, gulong max_rows)
 	_vte_row_data_init (&ring->cached_row);
 	ring->cached_row_num = (gulong) -1;
 
+	ring->visible_rows_hint = 0;
+
 	_vte_ring_validate(ring);
 }
 
@@ -353,6 +355,9 @@ _vte_ring_freeze_one_row (VteRing *ring)
 {
 	VteRowData *row;
 
+	// We should never even try to freeze if writable is less than a screenful from the end */
+	g_assert(ring->writable + ring->visible_rows_hint < ring->end);
+
 	if (G_UNLIKELY (ring->writable == ring->start))
 		_vte_ring_reset_streams (ring, ring->writable);
 
@@ -398,8 +403,10 @@ _vte_ring_discard_one_row (VteRing *ring)
 static void
 _vte_ring_maybe_freeze_one_row (VteRing *ring)
 {
-	if (G_LIKELY (ring->writable + ring->mask == ring->end))
+	if (G_LIKELY (ring->mask >= ring->visible_rows_hint && ring->writable + ring->mask + 1 == ring->end))
 		_vte_ring_freeze_one_row (ring);
+	else
+		_vte_ring_ensure_writable_room (ring);
 }
 
 static void
@@ -415,15 +422,18 @@ _vte_ring_ensure_writable_room (VteRing *ring)
 	gulong new_mask, old_mask, i, end;
 	VteRowData *old_array, *new_array;;
 
-	if (G_LIKELY (ring->writable + ring->mask > ring->end))
+	if (G_LIKELY (ring->mask >= ring->visible_rows_hint && ring->writable + ring->mask + 1 > ring->end))
 		return;
 
-	_vte_debug_print(VTE_DEBUG_RING, "Enlarging writable array.\n");
-
 	old_mask = ring->mask;
 	old_array = ring->array;
 
-	ring->mask = (ring->mask << 1) + 1;
+	do {
+		ring->mask = (ring->mask << 1) + 1;
+	} while (ring->mask < ring->visible_rows_hint || ring->writable + ring->mask + 1 <= ring->end);
+
+	_vte_debug_print(VTE_DEBUG_RING, "Enlarging writable array from %lu to %lu\n", old_mask, ring->mask);
+
 	ring->array = g_malloc0 (sizeof (ring->array[0]) * (ring->mask + 1));
 
 	new_mask = ring->mask;
@@ -586,6 +596,19 @@ _vte_ring_append (VteRing * ring)
 }
 
 
+/**
+ * _vte_ring_set_visible_rows_hint:
+ * @ring: a #VteRing
+ *
+ * Set the number of visible rows, a hint only for better performance.
+ */
+void
+_vte_ring_set_visible_rows_hint (VteRing *ring, gulong rows)
+{
+	ring->visible_rows_hint = rows;
+}
+
+
 static gboolean
 _vte_ring_write_row (VteRing *ring,
 		     GOutputStream *stream,
diff --git a/src/ring.h b/src/ring.h
index d39b690..66be9b0 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -62,6 +62,7 @@ struct _VteRing {
 	VteRowData cached_row;
 	gulong cached_row_num;
 
+	gulong visible_rows_hint;  // to keep at least a screenful of lines in memory, bug 646098 comment 12
 };
 
 #define _vte_ring_contains(__ring, __position) \
@@ -81,6 +82,7 @@ void _vte_ring_shrink (VteRing *ring, gulong max_len);
 VteRowData *_vte_ring_insert (VteRing *ring, gulong position);
 VteRowData *_vte_ring_append (VteRing *ring);
 void _vte_ring_remove (VteRing *ring, gulong position);
+void _vte_ring_set_visible_rows_hint (VteRing *ring, gulong rows);
 gboolean _vte_ring_write_contents (VteRing *ring,
 				   GOutputStream *stream,
 				   VteTerminalWriteFlags flags,
diff --git a/src/vte.c b/src/vte.c
index fa1c417..830a372 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -8126,6 +8126,9 @@ vte_terminal_set_size(VteTerminal *terminal, glong columns, glong rows)
 		terminal->column_count = columns;
 	}
 	if (old_rows != terminal->row_count || old_columns != terminal->column_count) {
+		_vte_ring_set_visible_rows_hint(terminal->pvt->normal_screen.row_data, terminal->row_count);
+		_vte_ring_set_visible_rows_hint(terminal->pvt->alternate_screen.row_data, terminal->row_count);
+
 		/* Always resize normal screen, even if alternate is visible: bug 415277 */
 		vte_terminal_screen_set_size(terminal, &terminal->pvt->normal_screen, old_columns, old_rows);
 		if (terminal->pvt->screen == &terminal->pvt->alternate_screen)
