[CLJ-898] Agent sends consume heap Created: 16/Dec/11 Updated: 01/Mar/13 Resolved: 27/Jan/12 |
|
| Status: | Closed |
| Project: | Clojure |
| Component/s: | None |
| Affects Version/s: | Release 1.3 |
| Fix Version/s: | Release 1.4 |
| Type: | Defect | Priority: | Major |
| Reporter: | Stuart Sierra | Assignee: | Stuart Sierra |
| Resolution: | Completed | Votes: | 1 |
| Labels: | None | ||
| Attachments: |
|
| Patch: | Code |
| Approval: | Ok |
| Description |
|
Simple demonstration: (defn update [state] (send *agent* update) (inc state)) (def a (agent 1)) (send a update) On Clojure 1.2.1, this runs forever with no problem. On 1.3.0, it throws "java.lang.OutOfMemoryError: Java heap space." The problem appears to be clojure.core/binding-conveyor-fn: each send creates a new Var binding frame, and nested send creates an infinite stack of frames. Also discussed at https://groups.google.com/d/topic/clojure/1qUNPZv3OYA/discussion |
| Comments |
| Comment by Tassilo Horn [ 16/Dec/11 11:46 AM ] |
|
I've just checked the code: send uses binding (which calls push-thread-bindings, creating a new Frame with non-null prev) inside which the binding-conveyor-fn captures the current frame. When the binding-conveyor-fn runs, the old Frame is restored, and since the wrapped function sends again, a new thread-binding is pushed on top of that. Hm, one way to get rid of the issue was not to capture the "real" current Frame in the binding-conveyor-fn but only a shallow copy, i.e., a Frame with the same bindings but no prev. I've tried that out, all tests still pass, and the example above won't grow heap without bounds. Patch attached. |
| Comment by Stuart Sierra [ 16/Dec/11 2:30 PM ] |
|
Screened. |
| Comment by Tassilo Horn [ 25/Jan/12 2:24 PM ] |
|
My fix had some small issue as David Miller pointed out correctly in Attached is a patch that fixes the quirk. |
| Comment by Tassilo Horn [ 25/Jan/12 2:25 PM ] |
|
Here's the fix for the fix. |