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:
parent
4ac62c1333
commit
f2a731e0a7
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue