{"action":"created","issue":{"url":"https://api.github.com/repos/ben-manes/caffeine/issues/67","repository_url":"https://api.github.com/repos/ben-manes/caffeine","labels_url":"https://api.github.com/repos/ben-manes/caffeine/issues/67/labels{/name}","comments_url":"https://api.github.com/repos/ben-manes/caffeine/issues/67/comments","events_url":"https://api.github.com/repos/ben-manes/caffeine/issues/67/events","html_url":"https://github.com/ben-manes/caffeine/issues/67","id":149148033,"number":67,"title":"Memory leak when eviction is stressed?","user":{"login":"cruftex","id":2668191,"avatar_url":"https://avatars.githubusercontent.com/u/2668191?v=3","gravatar_id":"","url":"https://api.github.com/users/cruftex","html_url":"https://github.com/cruftex","followers_url":"https://api.github.com/users/cruftex/followers","following_url":"https://api.github.com/users/cruftex/following{/other_user}","gists_url":"https://api.github.com/users/cruftex/gists{/gist_id}","starred_url":"https://api.github.com/users/cruftex/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cruftex/subscriptions","organizations_url":"https://api.github.com/users/cruftex/orgs","repos_url":"https://api.github.com/users/cruftex/repos","events_url":"https://api.github.com/users/cruftex/events{/privacy}","received_events_url":"https://api.github.com/users/cruftex/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":22,"created_at":"2016-04-18T13:17:12Z","updated_at":"2016-04-19T12:00:52Z","closed_at":null,"body":"Meanwhile I started experimenting on benchmarks that target at cache eviction operations.\r\n\r\nI constructed this benchmark:\r\n\r\n> Continuously access a cache of size 1M an ascending sequence, never producing any hit.\r\n> Each thread starts at another offset.\r\n\r\nSource:\r\nhttps://github.com/cache2k/cache2k-benchmark/blob/master/jmh-suite/src/main/java/org/cache2k/benchmark/jmh/suite/eviction/symmetrical/NeverHitBenchmark.java\r\n\r\n- JMH 1.11.3\r\n- VM version: JDK 1.8.0_74, VM 25.74-b02\r\n- VM options: -server -Xmx2G\r\n- caffeine 2.2.7\r\n\r\nThe benchmark run expands to the maximum heap. After a full GC still 1.4 Gb is used.\r\n\r\nA random sample with jmap during the benchmark iteration, shows:\r\n\r\n````\r\n$ jmap -histo:live ...\r\n\r\n num     #instances         #bytes  class name\r\n----------------------------------------------\r\n   1:      15486169      495557408  java.util.concurrent.ConcurrentHashMap$Node\r\n   2:      15484002      495488064  com.github.benmanes.caffeine.cache.NodeFactory$SStMS\r\n   3:      15484285      247748560  java.lang.Integer\r\n   4:       5247787      125946888  com.github.benmanes.caffeine.SingleConsumerQueue$Node\r\n   5:       5247786      125946864  com.github.benmanes.caffeine.cache.BoundedLocalCache$AddTask\r\n   6:            16       67128576  [Ljava.util.concurrent.ConcurrentHashMap$Node;\r\n   7:            77        8396088  [J\r\n   8:          6103         490616  [C\r\n...\r\n````\r\n\r\nI would have expected that the lagging eviction thread might be the cause, however, a benchmark run with 1,2 or 4 threads produces similar results. The memory isn't freeing up after the benchmark iteration is finished and two full GCs, as long as the cache reference is kept.\r\n\r\nIdeas?"},"comment":{"url":"https://api.github.com/repos/ben-manes/caffeine/issues/comments/211883004","html_url":"https://github.com/ben-manes/caffeine/issues/67#issuecomment-211883004","issue_url":"https://api.github.com/repos/ben-manes/caffeine/issues/67","id":211883004,"user":{"login":"ben-manes","id":378614,"avatar_url":"https://avatars.githubusercontent.com/u/378614?v=3","gravatar_id":"","url":"https://api.github.com/users/ben-manes","html_url":"https://github.com/ben-manes","followers_url":"https://api.github.com/users/ben-manes/followers","following_url":"https://api.github.com/users/ben-manes/following{/other_user}","gists_url":"https://api.github.com/users/ben-manes/gists{/gist_id}","starred_url":"https://api.github.com/users/ben-manes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ben-manes/subscriptions","organizations_url":"https://api.github.com/users/ben-manes/orgs","repos_url":"https://api.github.com/users/ben-manes/repos","events_url":"https://api.github.com/users/ben-manes/events{/privacy}","received_events_url":"https://api.github.com/users/ben-manes/received_events","type":"User","site_admin":false},"created_at":"2016-04-19T12:00:52Z","updated_at":"2016-04-19T12:00:52Z","body":"Yep. I'm never claiming one design is better, as all are trade-offs. Finding a balance is of course hard, and resolving to better handle a variety of workloads takes time to mature. Other approaches may very well work wonderfully.\r\n\r\nMaximizing cpu is definitely the goal of batch processing, but I/O usually starves it. Most caches are read centric and writes are very expensive, so some form of queuing exists there too (e.g. write-ahead logs). But that could have been the rub that I didn't account for as well, since druid batch centric. The bounded queue should help alleviate that now, without diminishing the primary goal of handling user-facing latencies."}}