diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js
index db3291f87..d7d50def9 100644
--- a/js/ui/lookingGlass.js
+++ b/js/ui/lookingGlass.js
@@ -582,6 +582,53 @@ ErrorLog.prototype = {
}
};
+function Memory() {
+ this._init();
+}
+
+Memory.prototype = {
+ _init: function() {
+ this.actor = new St.BoxLayout({ vertical: true });
+ this._glibc_uordblks = new St.Label();
+ this.actor.add(this._glibc_uordblks);
+
+ this._js_bytes = new St.Label();
+ this.actor.add(this._js_bytes);
+
+ this._gjs_boxed = new St.Label();
+ this.actor.add(this._gjs_boxed);
+
+ this._gjs_gobject = new St.Label();
+ this.actor.add(this._gjs_gobject);
+
+ this._gjs_function = new St.Label();
+ this.actor.add(this._gjs_function);
+
+ this._gjs_closure = new St.Label();
+ this.actor.add(this._gjs_closure);
+
+ this._gcbutton = new St.Button({ label: 'Full GC',
+ style_class: 'lg-obj-inspector-button' });
+ this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); }));
+ this.actor.add(this._gcbutton, { x_align: St.Align.START,
+ x_fill: false });
+
+ this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
+ },
+
+ _renderText: function() {
+ if (!this.actor.mapped)
+ return;
+ let memInfo = global.get_memory_info();
+ this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks;
+ this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes;
+ this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed;
+ this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
+ this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
+ this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
+ }
+};
+
function Extensions() {
this._init();
}
@@ -764,6 +811,9 @@ LookingGlass.prototype = {
this._errorLog = new ErrorLog();
notebook.appendPage('Errors', this._errorLog.actor);
+ this._memory = new Memory();
+ notebook.appendPage('Memory', this._memory.actor);
+
this._extensions = new Extensions();
notebook.appendPage('Extensions', this._extensions.actor);
diff --git a/src/shell-global.c b/src/shell-global.c
index e18dbc998..84b35db75 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -25,6 +25,11 @@
#include
#include
+/* Memory report bits */
+#ifdef HAVE_MALLINFO
+#include
+#endif
+
#include "shell-enum-types.h"
#include "shell-global-private.h"
#include "shell-jsapi-compat-private.h"
@@ -1126,6 +1131,38 @@ shell_global_maybe_gc (ShellGlobal *global)
gjs_context_maybe_gc (global->js_context);
}
+/**
+ * shell_global_get_memory_info:
+ * @global:
+ * @meminfo: (out caller-allocates): Output location for memory information
+ *
+ * Load process-global data about memory usage.
+ */
+void
+shell_global_get_memory_info (ShellGlobal *global,
+ ShellMemoryInfo *meminfo)
+{
+ JSContext *context;
+
+ memset (meminfo, 0, sizeof (meminfo));
+#ifdef HAVE_MALLINFO
+ {
+ struct mallinfo info = mallinfo ();
+ meminfo->glibc_uordblks = info.uordblks;
+ }
+#endif
+
+ context = gjs_context_get_native_context (global->js_context);
+
+ meminfo->js_bytes = JS_GetGCParameter (JS_GetRuntime (context), JSGC_BYTES);
+
+ meminfo->gjs_boxed = (unsigned int) gjs_counter_boxed.value;
+ meminfo->gjs_gobject = (unsigned int) gjs_counter_object.value;
+ meminfo->gjs_function = (unsigned int) gjs_counter_function.value;
+ meminfo->gjs_closure = (unsigned int) gjs_counter_closure.value;
+}
+
+
/**
* shell_global_notify_error:
* @global: a #ShellGlobal
diff --git a/src/shell-global.h b/src/shell-global.h
index c9d4f7c6f..d6f4c33a7 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -90,6 +90,21 @@ void shell_global_get_pointer (ShellGlobal *global,
void shell_global_gc (ShellGlobal *global);
void shell_global_maybe_gc (ShellGlobal *global);
+typedef struct {
+ guint glibc_uordblks;
+
+ guint js_bytes;
+
+ guint gjs_boxed;
+ guint gjs_gobject;
+ guint gjs_function;
+ guint gjs_closure;
+} ShellMemoryInfo;
+
+void shell_global_get_memory_info (ShellGlobal *global,
+ ShellMemoryInfo *meminfo);
+
+
gboolean shell_global_set_property_mutable (ShellGlobal *global,
const char *object,
const char *property,