This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Free memory_block pool
- From: Jan Hubicka <hubicka at ucw dot cz>
- To: gcc-patches at gcc dot gnu dot org, rguenther at suse dot de
- Date: Wed, 20 Nov 2019 16:03:14 +0100
- Subject: Free memory_block pool
Hi,
I have noticed that for Firefox around 1GB of peak memory use goes into
the fact that we never free memory_block_pool::freelist.
This patch adds memory_block_pool::trim which reduces freelist to a given
size. It is called from ggc_collect which is a convenient place to return
heap allocations too and fully freeed prior forking in ggc_collect.
I originaly was freeing block directly in memory_block_pool::release
but that makes it non-leaf function which prevents optimization.
So I decided to go this way we get tiny bit better code
given that we already have ggc_collect that is conveninet place
to do such a bookeeping.
Bootstrapped/regtested x86_64-linux, tested on Firefox build, OK?
Honza
* memory-block.h (memory_block_pool::freelist): New constant.
(memory_block_pool::clear_free_list): Rename to ...
(memory_block_pool::reduce_free_list): ... this.
(memory_block_pool::trim): New function.
(memory_block_pool::block_list): Add m_prev.
(memory_block_pool::m_num_blocks): New field.
(memory_block_pool::m_block_end): New field.
(memory_block_pool::allocate): Maintain m_num_blocks and m_blocks_end.
(memory_block_pool::release): Likewise.
* memory-block.cc (memory_block_pool::memory_block_pool): Initialize
new fields.
(memory_block_pool::clear_free_list): Rename to ...
(memory_block_pool::reduce_free_list): ... this one; free from end
and add NUM parameter.
(memory_block_pool::trim): New.
* ggc-page.c (ggc_collect): Call memory_block_pool::trim.
* lto.c: Call memory_block_pool::trim.
Index: memory-block.h
===================================================================
--- memory-block.h (revision 278464)
+++ memory-block.h (working copy)
@@ -28,12 +28,15 @@ class memory_block_pool
public:
/* Blocks have fixed size. This is necessary for sharing. */
static const size_t block_size = 64 * 1024;
+ /* Number of blocks we keep in the freelists. */
+ static const size_t freelist_size = 1024 * 1024 / block_size;
memory_block_pool ();
static inline void *allocate () ATTRIBUTE_MALLOC;
static inline void release (void *);
- void clear_free_list ();
+ static void trim (int nblocks = freelist_size);
+ void reduce_free_list (int);
private:
/* memory_block_pool singleton instance, defined in memory-block.cc. */
@@ -42,10 +45,13 @@ private:
struct block_list
{
block_list *m_next;
+ block_list *m_prev;
};
/* Free list. */
block_list *m_blocks;
+ block_list *m_blocks_end;
+ int m_num_blocks;
};
/* Allocate a single block. Reuse a previously returned block, if possible. */
@@ -57,6 +63,9 @@ memory_block_pool::allocate ()
void *result = instance.m_blocks;
instance.m_blocks = instance.m_blocks->m_next;
+ instance.m_num_blocks--;
+ if (!instance.m_blocks)
+ instance.m_blocks_end = NULL;
VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (result, block_size));
return result;
}
@@ -67,7 +76,12 @@ memory_block_pool::release (void *uncast
{
block_list *block = new (uncast_block) block_list;
block->m_next = instance.m_blocks;
+ if (instance.m_blocks)
+ instance.m_blocks->m_prev = block;
+ else
+ instance.m_blocks_end = block;
instance.m_blocks = block;
+ instance.m_num_blocks++;
VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS ((char *)uncast_block
+ sizeof (block_list),
Index: memory-block.cc
===================================================================
--- memory-block.cc (revision 278464)
+++ memory-block.cc (working copy)
@@ -26,18 +27,27 @@ along with GCC; see the file COPYING3.
/* Global singleton-like instance. */
memory_block_pool memory_block_pool::instance;
-memory_block_pool::memory_block_pool () : m_blocks (NULL) {}
+/* Default constructor. */
+memory_block_pool::memory_block_pool ()
+ : m_blocks (NULL), m_blocks_end (NULL), m_num_blocks (0)
+{
+}
-/* Return all blocks from free list to the OS. */
+/* Reduce free list to NUM blocks. */
void
-memory_block_pool::clear_free_list ()
+memory_block_pool::reduce_free_list (int num)
{
- while (m_blocks)
+ gcc_checking_assert (num >= 0);
+ while (m_num_blocks > num)
{
- block_list *next = m_blocks->m_next;
- XDELETEVEC (m_blocks);
- m_blocks = next;
+ block_list *prev = m_blocks_end->m_prev;
+ XDELETEVEC (m_blocks_end);
+ m_blocks_end = prev;
+ prev->m_next = NULL;
+ m_num_blocks--;
}
+ if (!m_num_blocks)
+ m_blocks = m_blocks_end = 0;
}
/* Allocate a chunk for obstack. Use the pool if requested chunk size matches
@@ -62,3 +72,10 @@ mempool_obstack_chunk_free (void *chunk)
else
XDELETEVEC (chunk);
}
+
+/* Return allocated memory back to malloc (and to system). */
+void
+memory_block_pool::trim (int num)
+{
+ instance.reduce_free_list (num);
+}
Index: ggc-page.c
===================================================================
--- ggc-page.c (revision 278464)
+++ ggc-page.c (working copy)
@@ -2186,6 +2186,9 @@ ggc_collect (void)
float allocated_last_gc =
MAX (G.allocated_last_gc, (size_t)param_ggc_min_heapsize * 1024);
+ /* It is a also good time to get memory block pool into limits. */
+ memory_block_pool::trim ();
+
float min_expand = allocated_last_gc * param_ggc_min_expand / 100;
if (G.allocated < allocated_last_gc + min_expand && !ggc_force_collect)
return;
Index: lto/lto.c
===================================================================
--- lto/lto.c (revision 278464)
+++ lto/lto.c (working copy)
@@ -387,6 +387,7 @@ lto_wpa_write_files (void)
temp_priority.safe_push (part->insns);
temp_filenames.safe_push (xstrdup (temp_filename));
}
+ memory_block_pool::trim (0);
for (int set = 0; set < MAX (lto_parallelism, 1); set++)
{