[gjs] gjs_context_maybe_gc: New function to hint GC may be necessary



commit 45b550d6790dba708eb94c7ee52f08d289f50b97
Author: Colin Walters <walters verbum org>
Date:   Thu Feb 3 15:06:17 2011 -0500

    gjs_context_maybe_gc: New function to hint GC may be necessary
    
    Consumers such as gnome-shell can use this instead of JS_MaybeGC();
    it better handles native glibc memory allocations.
    
    We also invoke it internally now after creating a GObject or a GBoxed
    derivative.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=640790

 configure.ac     |    3 +++
 gi/boxed.c       |    4 ++++
 gi/object.c      |    2 ++
 gjs/context.c    |   27 +++++++++++++++++++++++++++
 gjs/context.h    |    2 ++
 gjs/jsapi-util.c |   41 +++++++++++++++++++++++++++++++++++++++++
 gjs/jsapi-util.h |    2 ++
 7 files changed, 81 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index df33748..3da23d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,9 @@ AM_CONDITIONAL([ENABLE_COVERAGE], [test x$enable_coverage = xyes])
 # Checks for libraries.
 m4_define(gobject_required_version, 2.18.0)
 
+AC_CHECK_HEADERS([malloc.h])
+AC_CHECK_FUNCS(mallinfo)
+
 # Look for Spidermonkey. If js-config exists, use that;
 # otherwise we try some pkgconfig files from various distributions.
 
diff --git a/gi/boxed.c b/gi/boxed.c
index bd554f0..9bdd513 100644
--- a/gi/boxed.c
+++ b/gi/boxed.c
@@ -490,6 +490,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
                 GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
                 if (gtype != G_TYPE_NONE) {
                     priv->gboxed = g_boxed_copy(gtype, source_priv->gboxed);
+                    gjs_maybe_gc(context);
                     GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
                     return JS_TRUE;
                 }
@@ -544,6 +545,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
             }
 
             unthreadsafe_template_for_constructor.gboxed = NULL;
+            gjs_maybe_gc(context);
 
             retval = priv->gboxed != NULL;
             if (retval)
@@ -552,6 +554,8 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
         }
     }
 
+    gjs_maybe_gc(context);
+
     GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
 
     return JS_TRUE;
diff --git a/gi/object.c b/gi/object.c
index 40fdbb7..4e04dce 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -768,6 +768,8 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
 
     GJS_NATIVE_CONSTRUCTOR_FINISH(object_instance);
 
+    gjs_maybe_gc(context);
+
     return JS_TRUE;
 }
 
diff --git a/gjs/context.c b/gjs/context.c
index 218139f..4d8291c 100644
--- a/gjs/context.c
+++ b/gjs/context.c
@@ -825,6 +825,33 @@ gjs_context_new_with_search_path(char** search_path)
 }
 
 /**
+ * gjs_context_maybe_gc:
+ * @context: a #GjsContext
+ * 
+ * Similar to the Spidermonkey JS_MaybeGC() call which
+ * heuristically looks at JS runtime memory usage and
+ * may initiate a garbage collection. 
+ *
+ * This function always unconditionally invokes JS_MaybeGC(), but
+ * additionally looks at memory usage from the system malloc()
+ * when available, and if the delta has grown since the last run
+ * significantly, also initiates a full JavaScript garbage
+ * collection.  The idea is that since GJS is a bridge between
+ * JavaScript and system libraries, and JS objects act as proxies
+ * for these system memory objects, GJS consumers need a way to
+ * hint to the runtime that it may be a good idea to try a
+ * collection.
+ *
+ * A good time to call this function is when your application
+ * transitions to an idle state.
+ */ 
+void
+gjs_context_maybe_gc (GjsContext  *context)
+{
+    gjs_maybe_gc(context->context);
+}
+
+/**
  * gjs_context_get_all:
  *
  * Returns a newly-allocated list containing all known instances of #GjsContext.
diff --git a/gjs/context.h b/gjs/context.h
index 1c27ab5..3fc94e0 100644
--- a/gjs/context.h
+++ b/gjs/context.h
@@ -73,6 +73,8 @@ void            gjs_context_print_stack_to_buffer (GjsContext *js_context,
 
 void            gjs_context_print_stack_stderr    (GjsContext *js_context);
 
+void            gjs_context_maybe_gc              (GjsContext  *context);
+
 void            gjs_dumpstack                     (void);
 
 G_END_DECLS
diff --git a/gjs/jsapi-util.c b/gjs/jsapi-util.c
index c04712c..948f917 100644
--- a/gjs/jsapi-util.c
+++ b/gjs/jsapi-util.c
@@ -34,6 +34,9 @@
 
 #include <string.h>
 #include <math.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
 
 GQuark
 gjs_util_error_quark (void)
@@ -1517,3 +1520,41 @@ gjs_parse_args (JSContext  *context,
     JS_EndRequest(context);
     return JS_FALSE;
 }
+
+/**
+ * gjs_maybe_gc:
+ *
+ * Low level version of gjs_context_maybe_gc().
+ */
+void
+gjs_maybe_gc (JSContext *context)
+{
+    /* Picked this number out of the air basically; 16 megabytes
+     * "feels" good for all of mobile/embedded/GP.  We don't
+     * expect the cost of JS_GC() to be too high, but we
+     * also don't want to call it too often.
+     *
+     * A better approach actually may be to dynamically watch "free";
+     * how much memory we're using before we hit swap.  Even better of
+     * course: some component of the OS sends us a signal when we
+     * should be trying a GC.
+     */
+#define _GJS_MAYBE_GC_MALLOC_BYTES (16 * 1024 * 1024)
+
+    static int _gjs_last_maybe_gc_malloc_blocks = -1;
+    
+    JS_MaybeGC(context);
+
+#ifdef HAVE_MALLINFO
+    {
+        struct mallinfo mstats;
+        mstats = mallinfo();
+        if (mstats.uordblks < _gjs_last_maybe_gc_malloc_blocks || _gjs_last_maybe_gc_malloc_blocks == -1) {
+            _gjs_last_maybe_gc_malloc_blocks = mstats.uordblks;
+        } else if ((mstats.uordblks - _gjs_last_maybe_gc_malloc_blocks) > _GJS_MAYBE_GC_MALLOC_BYTES) {
+            JS_GC(context);
+            _gjs_last_maybe_gc_malloc_blocks = mstats.uordblks;
+        }
+    }     
+#endif    
+}
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 5129b24..5266ff0 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -386,6 +386,8 @@ gboolean    gjs_try_string_to_utf8            (JSContext       *context,
                                                char           **utf8_string_p,
                                                GError         **error);
 
+void gjs_maybe_gc (JSContext *context);
+
 G_END_DECLS
 
 #endif  /* __GJS_JSAPI_UTIL_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]