summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--gc.c165
2 files changed, 125 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index 8f3cda8715..e44a06391f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Sun Jun 8 19:17:59 2008 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add a build option "CALC_EXACT_MALLOC_SIZE".
+ This option enables to calculate exact size of current
+ allocated size by malloc(). You can access these information
+ with GC.malloc_allocated_size and GC.malloc_allocations.
+ This option consume additional memory as a header of each memory
+ object. This option also helps to find out xmalloc()/xfree()
+ consistency. If you get trouble with this option, some extension
+ using "free()" instead of "xfree()".
+ This options is disabled by default.
+
Sun Jun 8 18:15:38 2008 Koichi Sasada <ko1@atdot.net>
* array.c, bignum.c, cont.c, dir.c, dln.c, encoding.c, enumerator.c,
diff --git a/gc.c b/gc.c
index 3da18271ef..4dbf5d6c65 100644
--- a/gc.c
+++ b/gc.c
@@ -143,11 +143,17 @@ struct gc_list {
struct gc_list *next;
};
+#define CALC_EXACT_MALLOC_SIZE 0
+
typedef struct rb_objspace {
struct {
size_t limit;
size_t increase;
- } params;
+#if CALC_EXACT_MALLOC_SIZE
+ size_t allocated_size;
+ size_t allocations;
+#endif
+ } malloc_params;
struct {
size_t increment;
struct heaps_slot *ptr;
@@ -180,8 +186,8 @@ typedef struct rb_objspace {
#else
static rb_objspace_t rb_objspace = {{GC_MALLOC_LIMIT}, {HEAP_MIN_SLOTS}};
#endif
-#define malloc_limit objspace->params.limit
-#define malloc_increase objspace->params.increase
+#define malloc_limit objspace->malloc_params.limit
+#define malloc_increase objspace->malloc_params.increase
#define heap_slots objspace->heap.slots
#define heaps objspace->heap.ptr
#define heaps_length objspace->heap.length
@@ -307,8 +313,8 @@ gc_stress_set(VALUE self, VALUE bool)
return bool;
}
-void *
-ruby_vm_xmalloc(rb_objspace_t *objspace, size_t size)
+static void *
+vm_xmalloc(rb_objspace_t *objspace, size_t size)
{
void *mem;
@@ -317,6 +323,10 @@ ruby_vm_xmalloc(rb_objspace_t *objspace, size_t size)
}
if (size == 0) size = 1;
+#if CALC_EXACT_MALLOC_SIZE
+ size += sizeof(size_t);
+#endif
+
if (ruby_gc_stress || (malloc_increase+size) > malloc_limit) {
garbage_collect(objspace);
}
@@ -331,50 +341,18 @@ ruby_vm_xmalloc(rb_objspace_t *objspace, size_t size)
}
malloc_increase += size;
- return mem;
-}
-
-void *
-ruby_xmalloc(size_t size)
-{
- return ruby_vm_xmalloc(&rb_objspace, size);
-}
-
-void *
-ruby_vm_xmalloc2(rb_objspace_t *objspace, size_t n, size_t size)
-{
- size_t len = size * n;
- if (n != 0 && size != len / n) {
- rb_raise(rb_eArgError, "malloc: possible integer overflow");
- }
- return ruby_vm_xmalloc(objspace, len);
-}
-
-void *
-ruby_xmalloc2(size_t n, size_t size)
-{
- return ruby_vm_xmalloc2(&rb_objspace, n, size);
-}
-
-void *
-ruby_vm_xcalloc(rb_objspace_t *objspace, size_t n, size_t size)
-{
- void *mem;
-
- mem = ruby_vm_xmalloc2(objspace, n, size);
- memset(mem, 0, n * size);
+#if CALC_EXACT_MALLOC_SIZE
+ objspace->malloc_params.allocated_size += size;
+ objspace->malloc_params.allocations++;
+ ((size_t *)mem)[0] = size;
+ mem = (size_t *)mem + 1;
+#endif
return mem;
}
-void *
-ruby_xcalloc(size_t n, size_t size)
-{
- return ruby_vm_xcalloc(&rb_objspace, n, size);
-}
-
-void *
-ruby_vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
+static void *
+vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
{
void *mem;
@@ -384,6 +362,13 @@ ruby_vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
if (!ptr) return ruby_xmalloc(size);
if (size == 0) size = 1;
if (ruby_gc_stress) garbage_collect(objspace);
+
+#if CALC_EXACT_MALLOC_SIZE
+ size += sizeof(size_t);
+ objspace->malloc_params.allocated_size -= size;
+ ptr = (size_t *)ptr - 1;
+#endif
+
RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem) {
if (garbage_collect(objspace)) {
@@ -395,36 +380,75 @@ ruby_vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
}
malloc_increase += size;
+#if CALC_EXACT_MALLOC_SIZE
+ objspace->malloc_params.allocated_size += size;
+ ((size_t *)mem)[0] = size;
+ mem = (size_t *)mem + 1;
+#endif
+
return mem;
}
+static void
+vm_xfree(rb_objspace_t *objspace, void *ptr)
+{
+#if CALC_EXACT_MALLOC_SIZE
+ size_t size;
+ ptr = ((size_t *)ptr) - 1;
+ size = ((size_t*)ptr)[0];
+ objspace->malloc_params.allocated_size -= size;
+ objspace->malloc_params.allocations--;
+#endif
+
+ RUBY_CRITICAL(free(ptr));
+}
+
void *
-ruby_xrealloc(void *ptr, size_t size)
+ruby_xmalloc(size_t size)
{
- return ruby_vm_xrealloc(&rb_objspace, ptr, size);
+ return vm_xmalloc(&rb_objspace, size);
}
void *
-ruby_vm_xrealloc2(rb_objspace_t *objspace, void *ptr, size_t n, size_t size)
+ruby_xmalloc2(size_t n, size_t size)
{
size_t len = size * n;
if (n != 0 && size != len / n) {
- rb_raise(rb_eArgError, "realloc: possible integer overflow");
+ rb_raise(rb_eArgError, "malloc: possible integer overflow");
}
- return ruby_vm_xrealloc(objspace, ptr, len);
+ return vm_xmalloc(&rb_objspace, len);
+}
+
+void *
+ruby_xcalloc(size_t n, size_t size)
+{
+ void *mem = ruby_xmalloc2(n, size);
+ memset(mem, 0, n * size);
+
+ return mem;
+}
+
+void *
+ruby_xrealloc(void *ptr, size_t size)
+{
+ return vm_xrealloc(&rb_objspace, ptr, size);
}
void *
ruby_xrealloc2(void *ptr, size_t n, size_t size)
{
- return ruby_vm_xrealloc2(&rb_objspace, ptr, n, size);
+ size_t len = size * n;
+ if (n != 0 && size != len / n) {
+ rb_raise(rb_eArgError, "realloc: possible integer overflow");
+ }
+ return ruby_xrealloc(ptr, len);
}
void
ruby_xfree(void *x)
{
if (x)
- RUBY_CRITICAL(free(x));
+ vm_xfree(&rb_objspace, x);
}
@@ -2377,6 +2401,38 @@ gc_count(VALUE self)
return UINT2NUM((&rb_objspace)->count);
}
+#if CALC_EXACT_MALLOC_SIZE
+/*
+ * call-seq:
+ * GC.malloc_allocated_size -> Integer
+ *
+ * The allocated size by malloc().
+ *
+ * It returns the allocated size by malloc().
+ */
+
+static VALUE
+gc_malloc_allocated_size(VALUE self)
+{
+ return UINT2NUM((&rb_objspace)->malloc_params.allocated_size);
+}
+
+/*
+ * call-seq:
+ * GC.malloc_allocations -> Integer
+ *
+ * The number of allocated memory object by malloc().
+ *
+ * It returns the number of allocated memory object by malloc().
+ */
+
+static VALUE
+gc_malloc_allocations(VALUE self)
+{
+ return UINT2NUM((&rb_objspace)->malloc_params.allocations);
+}
+#endif
+
/*
* The <code>GC</code> module provides an interface to Ruby's mark and
* sweep garbage collection mechanism. Some of the underlying methods
@@ -2414,4 +2470,9 @@ Init_GC(void)
rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1);
+
+#if CALC_EXACT_MALLOC_SIZE
+ rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
+ rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
+#endif
}