Fix memory leak from the result wrapper struct itself

Data_Make_Struct always allocates memory for us, so we
need to explicitly free the pointer in the function we
pass to the GC, not just objects internal to us.

Without this change, a slow but constant growth can be
seen with the trivial code below:

    x = Mysql2::Client.new
    loop { x.query "select 1" }
This commit is contained in:
Eric Wong 2010-05-05 18:26:29 -07:00
parent 4ac62c1333
commit f2a731e0a7
2 changed files with 15 additions and 7 deletions

View File

@ -401,13 +401,20 @@ static VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
return obj; return obj;
} }
/* this may be called manually or during GC */
static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
if (wrapper && wrapper->resultFreed != 1) {
mysql_free_result(wrapper->result);
wrapper->resultFreed = 1;
}
}
/* this is called during GC */
static void rb_mysql_result_free(void * wrapper) { static void rb_mysql_result_free(void * wrapper) {
mysql2_result_wrapper * w = wrapper; mysql2_result_wrapper * w = wrapper;
if (w && w->resultFreed != 1) {
/* FIXME: this may call flush_use_result, which can hit the socket */ /* FIXME: this may call flush_use_result, which can hit the socket */
mysql_free_result(w->result); rb_mysql_result_free_result(w);
w->resultFreed = 1; xfree(wrapper);
}
} }
static void rb_mysql_result_mark(void * wrapper) { static void rb_mysql_result_mark(void * wrapper) {
@ -611,7 +618,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
if (row == Qnil) { if (row == Qnil) {
// we don't need the mysql C dataset around anymore, peace it // we don't need the mysql C dataset around anymore, peace it
rb_mysql_result_free(wrapper); rb_mysql_result_free_result(wrapper);
return Qnil; return Qnil;
} }
@ -621,7 +628,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
} }
if (wrapper->lastRowProcessed == wrapper->numberOfRows) { if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
// we don't need the mysql C dataset around anymore, peace it // we don't need the mysql C dataset around anymore, peace it
rb_mysql_result_free(wrapper); rb_mysql_result_free_result(wrapper);
} }
} }

View File

@ -67,6 +67,7 @@ static VALUE rb_mysql_result_fetch_row(int argc, VALUE * argv, VALUE self);
static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self); static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self);
static void rb_mysql_result_free(void * wrapper); static void rb_mysql_result_free(void * wrapper);
static void rb_mysql_result_mark(void * wrapper); static void rb_mysql_result_mark(void * wrapper);
static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper);
/* /*
* used to pass all arguments to mysql_real_connect while inside * used to pass all arguments to mysql_real_connect while inside