Commits

camlspotter committed b97135d

fixed memory leak around ocaml closure wrapper

Comments (0)

Files changed (6)

 
 .DEFAULT: $(OCamlProgram test, test)
 .DEFAULT: $(OCamlProgram test_bug1, test_bug1)
+
+.SUBDIRS: tests
 
 void opycaml_decref(value obj){
     PyObject *o = PyObject_val(obj);
+    PyObject *p = PyCFunction_GetSelf(o);
+//    if( PyCFunction_Check(o) ){ 
+//        fprintf(stderr, "PYCFunction DECR! %d(%d) =>\n", 
+//                o->ob_refcnt,
+//                p->ob_refcnt
+//                );
+//    }
     if( o ) Py_DECREF(o);
-    return;
+//    if( PyCFunction_Check(o) ){ 
+//        fprintf(stderr, "PYCFunction DECR! => %d(%d)\n", 
+//                o->ob_refcnt,
+//                p->ob_refcnt);
+//    }
+
+//     if( PyCFunction_Check(o) ){ fprintf(stderr, "PYCFunction DECR! => %d\n", 
+//                                         o->ob_refcnt);
+//     }
+//     if( PyCObject_Check(o) ){ fprintf(stderr, "PYCFunction DECR! => %d\n", 
+//                                       o->ob_refcnt);
+//     }
+//     return;
 }
 
 value opycaml_address(value obj){
     wrapped->methodDef.ml_doc = "ocaml closure";
     
     PyObject *cobject = PyCObject_FromVoidPtr(wrapped, opycaml_remove_wrap);
-    return Val_PyObject(PyCFunction_New(&wrapped->methodDef, cobject), 0);
+    PyCFunction *cfunction = PyCFunction_New(&wrapped->methodDef, cobject);
+    // PyCFunction_New incrmenets cobject refcnt to 2. We here it make back to 1.  
+    if( cobject->ob_refcnt == 2 /* must be always true */ ){ Py_DECREF(cobject); }
+    return Val_PyObject(cfunction, 0);
 }
+OCAML_LIBS = ../opycaml
+OCAMLFLAGS += -I ..
+
+.DEFAULT: $(OCamlProgram from_string_iteration, from_string_iteration)
+.DEFAULT: $(OCamlProgram set_closure_string, set_closure_string)

tests/from_string_iteration.ml

+open Opycaml.Api
+
+let f n = 
+  let o = Py.String.fromString "hello world" in
+  if n mod 1000 = 0 then Base.debug "o" o;
+  if n mod 10000 = 0 then Gc.print_stat stderr
+;;
+
+let _ = 
+  for i = 0 to 1000000 do
+    f i
+  done

tests/set_closure_string.ml

+open Opycaml.Api
+
+let _ = Base.initialize ()
+
+let m = Module.new_ "x"
+let _ = Module.setToSys "x" m
+
+let _ = Format.eprintf "test start@."
+
+let freed = ref 0
+let finalize = fun _ -> incr freed
+
+let f n = 
+  let f = fun args -> 
+    Format.eprintf "f(%d)@." n;
+    Object.obj (Base.none ())
+  in
+  Gc.finalise finalize f; 
+  Module.setClosureString m "f" f;
+  if n mod 1000 = 0 then begin
+    Format.eprintf "*** %d@." n;
+    Opycaml.Utils.Gc.report ();
+    Format.eprintf "freed %d@." !freed
+  end
+;;
+
+let _ = 
+  for i = 0 to 100000 do
+    f i
+  done
     in
     iteri f 0 list
 end
+
+module Gc = struct
+  let report () = 
+    let stat = Gc.stat () in
+    Format.eprintf "live_words: %d / maj-cor: %d@." stat.Gc.live_words stat.Gc.major_collections
+end