[gjs] gjs_context_maybe_gc: New function to hint GC may be necessary
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] gjs_context_maybe_gc: New function to hint GC may be necessary
- Date: Fri, 4 Feb 2011 23:12:03 +0000 (UTC)
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]