{"action":"created","issue":{"url":"https://api.github.com/repos/Hopac/Hopac/issues/107","repository_url":"https://api.github.com/repos/Hopac/Hopac","labels_url":"https://api.github.com/repos/Hopac/Hopac/issues/107/labels{/name}","comments_url":"https://api.github.com/repos/Hopac/Hopac/issues/107/comments","events_url":"https://api.github.com/repos/Hopac/Hopac/issues/107/events","html_url":"https://github.com/Hopac/Hopac/issues/107","id":160882661,"number":107,"title":"Hunting for memory leak","user":{"login":"vasily-kirichenko","id":873919,"avatar_url":"https://avatars.githubusercontent.com/u/873919?v=3","gravatar_id":"","url":"https://api.github.com/users/vasily-kirichenko","html_url":"https://github.com/vasily-kirichenko","followers_url":"https://api.github.com/users/vasily-kirichenko/followers","following_url":"https://api.github.com/users/vasily-kirichenko/following{/other_user}","gists_url":"https://api.github.com/users/vasily-kirichenko/gists{/gist_id}","starred_url":"https://api.github.com/users/vasily-kirichenko/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vasily-kirichenko/subscriptions","organizations_url":"https://api.github.com/users/vasily-kirichenko/orgs","repos_url":"https://api.github.com/users/vasily-kirichenko/repos","events_url":"https://api.github.com/users/vasily-kirichenko/events{/privacy}","received_events_url":"https://api.github.com/users/vasily-kirichenko/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2016-06-17T13:00:11Z","updated_at":"2016-06-19T08:51:08Z","closed_at":null,"body":"I've managed to make a minimal repro. So, we have a couple of servers which waits for messages from same couple of channels, but in difference precedence: first server (`worker`) prefer the first channel, second one - the second channel.\r\n\r\n```fsharp\r\nopen Hopac\r\nopen Hopac.Infixes\r\nopen System\r\n\r\ntype State = { Count: int }\r\n\r\n[<EntryPoint>]\r\nlet main _ = \r\n    let worker alt =\r\n        Job.iterateServer { Count = 0 } (fun s -> \r\n            alt ^-> fun _ -> { s with Count = s.Count + 1 }\r\n        ) |> queue\r\n\r\n    let ch1, ch2 = Ch(), Ch()\r\n\r\n    let _worker1 = worker <| Alt.choose [ch1; ch2]\r\n    let _worker2 = worker <| Alt.choose [ch2; ch1]\r\n\r\n    while true do\r\n        printfn \"Press a key to send a task\"\r\n        Console.ReadKey() |> ignore\r\n        ch1 *<- () |> run\r\n    0\r\n```\r\nAfter 10 iterations dotMemory shows the following picture:\r\n![image](https://cloud.githubusercontent.com/assets/873919/16176136/726f22de-360e-11e6-9290-8cbdaf9bb27d.png)\r\n\r\nRetention paths for `State` objects, for example, are as follows:\r\n![image](https://cloud.githubusercontent.com/assets/873919/16176152/004fdc92-360f-11e6-9b5c-dd91eabafc39.png)\r\n![image](https://cloud.githubusercontent.com/assets/873919/16176155/0c0bb056-360f-11e6-9fb1-39be087c1ec7.png)\r\n\r\nIf I comment out `let _worker2 = worker <| Alt.choose [ch2; ch1]`, leaving only one worker, the leak is completely gone.\r\n\r\nThe real task is as following:\r\n* there are a number of channels\r\n* there are a number of workers, each of which should always prefer messages from one of the channels, if there is no messages in that channel, the worker should get messages from all other channels, randomly\r\nIn the real code workers synchronize on things like this: `preferableCh <|> Alt.chooser otherChs`, but the minimal repro above demonstrate the leak as well."},"comment":{"url":"https://api.github.com/repos/Hopac/Hopac/issues/comments/226986603","html_url":"https://github.com/Hopac/Hopac/issues/107#issuecomment-226986603","issue_url":"https://api.github.com/repos/Hopac/Hopac/issues/107","id":226986603,"user":{"login":"vasily-kirichenko","id":873919,"avatar_url":"https://avatars.githubusercontent.com/u/873919?v=3","gravatar_id":"","url":"https://api.github.com/users/vasily-kirichenko","html_url":"https://github.com/vasily-kirichenko","followers_url":"https://api.github.com/users/vasily-kirichenko/followers","following_url":"https://api.github.com/users/vasily-kirichenko/following{/other_user}","gists_url":"https://api.github.com/users/vasily-kirichenko/gists{/gist_id}","starred_url":"https://api.github.com/users/vasily-kirichenko/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vasily-kirichenko/subscriptions","organizations_url":"https://api.github.com/users/vasily-kirichenko/orgs","repos_url":"https://api.github.com/users/vasily-kirichenko/repos","events_url":"https://api.github.com/users/vasily-kirichenko/events{/privacy}","received_events_url":"https://api.github.com/users/vasily-kirichenko/received_events","type":"User","site_admin":false},"created_at":"2016-06-19T08:51:08Z","updated_at":"2016-06-19T08:51:08Z","body":"Addition: sending a message to `ch2` like `ch2 *<- () |> run` frees up all the stuck objects, but in the real code there are channels which are not given messages for days, so it's not a solution.\r\n\r\nWhat's interesting, adding `timeOutMillis 1000 ^->. s` alternative to the worker does not solve the problem."}}
{"actor":{"display_login":"vasily-kirichenko"}}