Eliminate 'memory leak' code defect for scratch-allocated memory
authorIvan Maidanski <ivmai@mail.ru>
Thu, 22 Dec 2016 08:05:41 +0000 (11:05 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Thu, 22 Dec 2016 08:05:41 +0000 (11:05 +0300)
Reuse memory allocated by GC_scratch_alloc and GET_MEM in GC heap
if possible.

* backgraph.c (push_in_progress): Replace in_progress_size==0 with
in_progress_space==NULL (to ensure BCOPY argument is non-NULL);
eliminate code duplication regarding GC_add_to_our_memory call;
call GC_scratch_recycle_no_gww (for old in_progress_space value) unless
GWW_VDB (and remove corresponding FIXME).
* dyn_load.c [IRIX5 || USE_PROC_FOR_LIBRARIES && !LINUX]
(GC_register_dynamic_libraries): Call GC_scratch_recycle_no_gww (for
old addr_map and current_sz values).
* include/private/gc_priv.h [!GWW_VDB] (GC_scratch_recycle_no_gww): New
internal macro.
* include/private/gc_priv.h (GC_scratch_recycle_inner): New prototype.
* mark.c (GC_scratch_recycle_inner): New function (move code portion
from alloc_mark_stack).
* mark.c (alloc_mark_stack): Call GC_scratch_recycle_inner (if
recycle_old).
* os_dep.c [NEED_PROC_MAPS] (GC_get_maps): Call GC_scratch_recycle_no_gww
(for old maps_buf and maps_buf_sz values).
* os_dep.c [PROC_VDB] (GC_read_dirty): Call GC_scratch_recycle_no_gww
(for old GC_proc_buf and GC_proc_buf_size values).

backgraph.c
dyn_load.c
include/private/gc_priv.h
mark.c
os_dep.c

index 6e7a6bb..743f266 100644 (file)
@@ -129,26 +129,32 @@ static size_t n_in_progress = 0;
 static void push_in_progress(ptr_t p)
 {
   if (n_in_progress >= in_progress_size) {
-    if (in_progress_size == 0) {
+    ptr_t * new_in_progress_space;
+
+    if (NULL == in_progress_space) {
       in_progress_size = ROUNDUP_PAGESIZE_IF_MMAP(INITIAL_IN_PROGRESS
                                                         * sizeof(ptr_t))
                                 / sizeof(ptr_t);
-      in_progress_space = (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
-      GC_add_to_our_memory((ptr_t)in_progress_space,
-                           in_progress_size * sizeof(ptr_t));
+      new_in_progress_space =
+                        (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
     } else {
-      ptr_t * new_in_progress_space;
       in_progress_size *= 2;
       new_in_progress_space = (ptr_t *)
                                 GET_MEM(in_progress_size * sizeof(ptr_t));
-      GC_add_to_our_memory((ptr_t)new_in_progress_space,
-                           in_progress_size * sizeof(ptr_t));
       if (new_in_progress_space != NULL)
         BCOPY(in_progress_space, new_in_progress_space,
               n_in_progress * sizeof(ptr_t));
-      in_progress_space = new_in_progress_space;
-      /* FIXME: This just drops the old space.  */
     }
+    GC_add_to_our_memory((ptr_t)new_in_progress_space,
+                         in_progress_size * sizeof(ptr_t));
+#   ifndef GWW_VDB
+      GC_scratch_recycle_no_gww(in_progress_space,
+                                n_in_progress * sizeof(ptr_t));
+#   elif defined(LINT2)
+      /* TODO: implement GWW-aware recycling as in alloc_mark_stack */
+      GC_noop1((word)in_progress_space);
+#   endif
+    in_progress_space = new_in_progress_space;
   }
   if (in_progress_space == 0)
       ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
index dbc145d..beda2b8 100644 (file)
@@ -816,6 +816,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
                    ": fd = %d, errno = %d", fd, errno);
     }
     if (needed_sz >= current_sz) {
+        GC_scratch_recycle_no_gww(addr_map,
+                                  (size_t)current_sz * sizeof(prmap_t));
         current_sz = needed_sz * 2 + 1;
                         /* Expansion, plus room for 0 record */
         addr_map = (prmap_t *)GC_scratch_alloc(
index 6be33a2..71c8a20 100644 (file)
@@ -1807,6 +1807,14 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes);
                                 /* small objects.  Deallocation is not  */
                                 /* possible.  May return NULL.          */
 
+#ifdef GWW_VDB
+  /* GC_scratch_recycle_no_gww() not used.      */
+#else
+# define GC_scratch_recycle_no_gww GC_scratch_recycle_inner
+#endif
+GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes);
+                                /* Reuse the memory region by the heap. */
+
 /* Heap block layout maps: */
 GC_INNER GC_bool GC_add_map_entry(size_t sz);
                                 /* Add a heap block map for objects of  */
diff --git a/mark.c b/mark.c
index f5b9dc4..e5c8921 100644 (file)
--- a/mark.c
+++ b/mark.c
@@ -1260,6 +1260,27 @@ GC_INNER void GC_help_marker(word my_mark_no)
 
 #endif /* PARALLEL_MARK */
 
+GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes)
+{
+  if (ptr != NULL) {
+    size_t page_offset = (word)ptr & (GC_page_size - 1);
+    size_t displ = 0;
+    size_t recycled_bytes;
+
+    GC_ASSERT(bytes != 0);
+    GC_ASSERT(GC_page_size != 0);
+    /* TODO: Assert correct memory flags if GWW_VDB */
+    if (page_offset != 0)
+      displ = GC_page_size - page_offset;
+    recycled_bytes = (bytes - displ) & ~(GC_page_size - 1);
+    GC_COND_LOG_PRINTF("Recycle %lu/%lu scratch-allocated bytes at %p\n",
+                       (unsigned long)recycled_bytes, (unsigned long)bytes,
+                       ptr);
+    if (recycled_bytes > 0)
+      GC_add_to_heap((struct hblk *)((word)ptr + displ), recycled_bytes);
+  }
+}
+
 /* Allocate or reallocate space for mark stack of size n entries.  */
 /* May silently fail.                                              */
 static void alloc_mark_stack(size_t n)
@@ -1281,16 +1302,8 @@ static void alloc_mark_stack(size_t n)
         if (new_stack != 0) {
           if (recycle_old) {
             /* Recycle old space */
-              size_t page_offset = (word)GC_mark_stack & (GC_page_size - 1);
-              size_t size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
-              size_t displ = 0;
-
-              if (0 != page_offset) displ = GC_page_size - page_offset;
-              size = (size - displ) & ~(GC_page_size - 1);
-              if (size > 0) {
-                GC_add_to_heap((struct hblk *)
-                                ((word)GC_mark_stack + displ), (word)size);
-              }
+            GC_scratch_recycle_inner(GC_mark_stack,
+                        GC_mark_stack_size * sizeof(struct GC_ms_entry));
           }
           GC_mark_stack = new_stack;
           GC_mark_stack_size = n;
index 6cbd3f1..987158a 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -201,6 +201,7 @@ GC_INNER char * GC_get_maps(void)
             int f;
 
             while (maps_size >= maps_buf_sz) {
+              GC_scratch_recycle_no_gww(maps_buf, maps_buf_sz);
               /* Grow only by powers of 2, since we leak "too small" buffers.*/
               while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
               maps_buf = GC_scratch_alloc(maps_buf_sz);
@@ -3603,6 +3604,7 @@ GC_INNER void GC_read_dirty(GC_bool output_unneeded)
              (signed_word)GC_proc_buf_size);
         new_buf = GC_scratch_alloc(new_size);
         if (new_buf != 0) {
+            GC_scratch_recycle_no_gww(bufp, GC_proc_buf_size);
             GC_proc_buf = bufp = new_buf;
             GC_proc_buf_size = new_size;
         }