From b7ff56db631be7416cf228dff89cb23d753e4ec8 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sun, 20 Nov 2016 09:00:50 +0100 Subject: fixed glib warnings about using g_mem_set_vtable() and revised memory limiting * we were basing the glib allocators on throwing std::bad_alloc just like the C++ operators. However, this always was unsafe since we were throwing exceptions across plain-C frames (Glib). Also, the memory vtable has been deprecated in Glib, resulting in ugly warnings. * Instead, we now let the C++ new/delete operators work like Glib by basing them on g_malloc/g_slice. This means they will assert and the application will terminate abnormally in case of OOM. OOMs cannot be handled properly anyway, so it is more important to have a good memory limiting mechanism. * Memory limiting has been completely revised. Instead of approximating undo stack sizes using virtual methods (which is unprecise and comes with a performance penalty), we now use a common base class SciTECO::Object to count the memory required by all objects allocated within SciTECO. This is less precise than using global replacement new/deletes which would allow us to control allocations in all C++ code including Scintilla, but they are only supported as of C++14 (GCC 5) and adding compile-time checks would be cumbersome. In any case, we're missing Glib allocations (esp. strings). * As a platform-specific extension, on Linux/glibc we use mallinfo() to count the exact memory usage of the process. On Windows, we use GetProcessMemoryInfo() -- the latter implementation is currently UNTESTED. * We use g_malloc() for new/delete operators when there is malloc_trim() since g_slice does not free heap chunks properly (probably does its own mmap()ing), rendering malloc_trim() ineffective. We've also benchmarked g_slice on Linux/glib (malloc_trim() shouldn't be available elsewhere) and found that it brings no significant performance benefit. On all other platforms, we use g_slice since it is assumed that it at least does not hurt. The new g_slice based allocators should be tested on MSVCRT since I assume that they bring a significant performance benefit on Windows. * Memory limiting does now work in batch mode as well and is still enabled by default. * The old UndoTokenWithSize CRTP hack could be removed. UndoStack operations should be a bit faster now. But on the other hand, there will be an overhead due to repeated memory limit checking on every processed character. --- src/parser.cpp | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'src/parser.cpp') diff --git a/src/parser.cpp b/src/parser.cpp index dd936f6..05694a2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -21,13 +21,13 @@ #include #include -#include #include #include #include #include "sciteco.h" +#include "memory.h" #include "string-utils.h" #include "interface.h" #include "undo.h" @@ -107,8 +107,11 @@ Execute::step(const gchar *macro, gint stop_pos) { try { /* - * convert bad_alloc and other C++ standard - * library exceptions + * Convert bad_alloc and other C++ standard + * library exceptions. + * bad_alloc should no longer be thrown, though + * since new/delete uses Glib allocations and we + * uniformly terminate abnormally in case of OOM. */ try { while (macro_pc < stop_pos) { @@ -121,6 +124,8 @@ Execute::step(const gchar *macro, gint stop_pos) if (interface.is_interrupted()) throw Error("Interrupted"); + memlimit.check(); + State::input(macro[macro_pc]); macro_pc++; } @@ -2305,23 +2310,31 @@ StateECommand::custom(gchar chr) * of buffers in the ring. * (\fBread-only\fP) * .IP 2 - * The current undo stack memory limit in bytes. + * The current memory limit in bytes. * This limit helps to prevent dangerous out-of-memory * conditions (e.g. resulting from infinite loops) by - * approximating the memory used by \*(ST's undo stack and is only - * effective in interactive mode. - * Commands which would exceed that limit fail instead. + * constantly sampling the memory requirements of \*(ST. + * Note that not all platforms support precise measurements + * of the current memory usage \(em \*(ST will fall back + * to an approximation which might be less than the actual + * usage on those platforms. + * Memory limiting is effective in batch and interactive mode. + * Commands which would exceed that limit will fail instead + * allowing users to recover in interactive mode, e.g. by + * terminating the command line. * When getting, a zero value indicates that memory limiting is * disabled. * Setting a value less than or equal to 0 as in * \(lq0,2EJ\(rq disables the limit. * \fBWarning:\fP Disabling memory limiting may provoke - * uncontrollable out-of-memory errors in long running - * or infinite loops. - * Setting a new limit may fail if the current undo stack - * is too large for the new limit \(em if this happens - * you may have to clear your command-line first. - * Undo stack memory limiting is enabled by default. + * out-of-memory errors in long running or infinite loops + * (interactive mode) that result in abnormal program + * termination. + * Setting a new limit may fail if the current memory + * requirements are too large for the new limit \(em if + * this happens you may have to clear your command-line + * first. + * Memory limiting is enabled by default. * .IP 3 * This \fBwrite-only\fP property allows redefining the * first 16 entries of the terminal color palette \(em a @@ -2370,7 +2383,7 @@ StateECommand::custom(gchar chr) enum { EJ_USER_INTERFACE = 0, EJ_BUFFERS, - EJ_UNDO_MEMORY_LIMIT, + EJ_MEMORY_LIMIT, EJ_INIT_COLOR }; tecoInt property; @@ -2382,8 +2395,8 @@ StateECommand::custom(gchar chr) tecoInt value = expressions.pop_num_calc(); switch (property) { - case EJ_UNDO_MEMORY_LIMIT: - undo.set_memory_limit(MAX(0, value)); + case EJ_MEMORY_LIMIT: + memlimit.set_limit(MAX(0, value)); break; case EJ_INIT_COLOR: @@ -2419,8 +2432,8 @@ StateECommand::custom(gchar chr) expressions.push(ring.get_id(ring.last())); break; - case EJ_UNDO_MEMORY_LIMIT: - expressions.push(undo.memory_limit); + case EJ_MEMORY_LIMIT: + expressions.push(memlimit.limit); break; default: -- cgit v1.2.3