[m-rev.] for review: Fix unexpected memory retention by mvars.

Peter Wang novalazy at gmail.com
Thu Apr 11 12:33:23 AEST 2013


Even after "taking" a value out of an mvar, the reference to the value
actually still remained.  This may lead to higher than expected memory
usage.

(Aside: putting a dummy value into an mvar is a bad idea and unsolved by
this change.  In low-level C grades whatever value happened to be in the
register for the value argument in the mvar.put call will be placed into
the mvar, and it might point to some large value which is otherwise
collectable.)

library/thread.mvar.m:
	Make mvar.take and mvar.try_take clear the underlying mutvar
	after retrieving the value.

library/mutvar.m:
	Add clear_mutvar in support.

diff --git a/library/mutvar.m b/library/mutvar.m
index 057a7be..b07bdc6 100644
--- a/library/mutvar.m
+++ b/library/mutvar.m
@@ -57,6 +57,15 @@ XXX `ui' modes don't work yet
 :-        pred set_mutvar(ui, di) is det.
 */
 
+    % Destructively clear a reference to avoid retaining the value.
+    %
+:- impure pred clear_mutvar(mutvar(T)) is det.
+:-        mode clear_mutvar(in) is det.
+/*
+XXX `ui' modes don't work yet
+:-        pred clear_mutvar(ui) is det.
+*/
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -66,6 +75,7 @@ XXX `ui' modes don't work yet
 :- pragma inline(new_mutvar0/1).
 :- pragma inline(get_mutvar/2).
 :- pragma inline(set_mutvar/2).
+:- pragma inline(clear_mutvar/1).
 
 %-----------------------------------------------------------------------------%
 
@@ -107,6 +117,13 @@ new_mutvar(X, Ref) :-
     *(MR_Word *) Ref = X;
 ").
 
+:- pragma foreign_proc("C",
+    clear_mutvar(Ref::in),
+    [will_not_call_mercury, thread_safe],
+"
+    *(MR_Word *) Ref = 0;
+").
+
 %-----------------------------------------------------------------------------%
 %
 % C# implementation
@@ -135,6 +152,13 @@ new_mutvar(X, Ref) :-
     Ref[0] = X;
 ").
 
+:- pragma foreign_proc("C#",
+    clear_mutvar(Ref::in),
+    [will_not_call_mercury, thread_safe],
+"
+    Ref[0] = null;
+").
+
 %-----------------------------------------------------------------------------%
 %
 % Java implementation
@@ -177,6 +201,13 @@ new_mutvar(X, Ref) :-
     Ref.object = X;
 ").
 
+:- pragma foreign_proc("Java",
+    clear_mutvar(Ref::in),
+    [will_not_call_mercury, thread_safe],
+"
+    Ref.object = null;
+").
+
 %-----------------------------------------------------------------------------%
 %
 % Erlang implementation
@@ -207,6 +238,13 @@ new_mutvar(X, Ref) :-
     ets:insert(Ref, {value, X})
 ").
 
+:- pragma foreign_proc("Erlang",
+    clear_mutvar(Ref::in),
+    [will_not_call_mercury, thread_safe],
+"
+    ets:delete(Ref, value)
+").
+
 %-----------------------------------------------------------------------------%
 :- end_module mutvar.
 %-----------------------------------------------------------------------------%
diff --git a/library/thread.mvar.m b/library/thread.mvar.m
index 18b695f..42ae67a 100644
--- a/library/thread.mvar.m
+++ b/library/thread.mvar.m
@@ -98,6 +98,8 @@ mvar.take(mvar(Full, Empty, Ref), Data, !IO) :-
     promise_pure (
         semaphore.wait(Full, !IO),
         impure get_mutvar(Ref, Data),
+        % Avoid unwanted memory retention.
+        impure clear_mutvar(Ref),
         semaphore.signal(Empty, !IO)
     ).
 
@@ -107,6 +109,8 @@ mvar.try_take(mvar(Full, Empty, Ref), MaybeData, !IO) :-
         (
             Success = yes,
             impure get_mutvar(Ref, Data),
+            % Avoid unwanted memory retention.
+            impure clear_mutvar(Ref),
             semaphore.signal(Empty, !IO),
             MaybeData = yes(Data)
         ;




More information about the reviews mailing list