Dead Continuation cause resource leak?
Alex Otenko
oleksandr.otenko at gmail.com
Thu May 28 14:51:46 UTC 2020
I get that. What seems to be a problem, is that the language promise cannot
be easily translated into Continuations.
Case in point:
https://github.com/forax/loom-fiber/blob/master/src/main/java/fr.umlv.loom/fr/umlv/loom/Generators.java#L74
This is an example, a technology demonstrator, yes, but...
consumer potentially has a try-finally block encompassing the invocation of
consumer on lines 54...57. (Consider the closing bracket is the actual last
statement, so it's easier to see the problem).
The yield returns us to line 73.
What happens if this.action.accept throws? I presume we never get to line
74, because consumer is oblivious of the need to yield, nor does it have a
way to communicate that yield has failed.
Ok, suppose, we reach line 74 due to a Throwable. What reasoning can be
used to determine that consumer's try-finally does not need attending?
(That is, returning back to line 57, perhaps with a Throwable)
Alex
On Thu, 28 May 2020, 12:54 Ron Pressler, <ron.pressler at oracle.com> wrote:
> But the question was about a liveness property, not a safety property.
> *If* the
> continuation (or any thread, really) terminates *then* finally will run
> (actually,
> this, too, is not a guarantee we make, but that’s a different matter). If
> a
> continuation never terminates, or if a thread sleeps forever, then there is
> no guarantee that finally blocks will ever run.
>
> It is up to the scheduler and blocking constructs — just as in the case of
> the OS — to make any kind of liveness guarantees (or attempts).
>
> — Ron
>
>
> On 28 May 2020 at 12:30:45, Alex Otenko (oleksandr.otenko at gmail.com)
> wrote:
>
> Yes, but the JVM offers safety of try-finally. So finally is always
> executed, if the enclosed block terminates. Implementing something of the
> kind every time it is needed in CPS is not easy.
>
> Alex
>
> On Thu, 28 May 2020, 11:09 Ron Pressler, <ron.pressler at oracle.com> wrote:
>
>> A continuation, or a virtual thread for that matter, that becomes
>> unreachable before termination
>> corresponds to an ordinary platform thread that sleeps forever. Neither
>> the JDK nor the OS makes
>> liveness guarantees about code.
>>
>> Having said that, a virtual thread can become unreachable before
>> termination only due to a serious
>> bug. When it is mounted, a reference to it is held by the scheduler or
>> else it would be able to schedule
>> it, and when blocked (and unmounted) a reference to it is held by the
>> blocking construct, or else
>> it would never be able to unblock it.
>>
>> — Ron
>>
>>
>> On 28 May 2020 at 07:43:09, 施慧 (kalinshi at qq.com) wrote:
>>
>> Hi All,
>>
>>
>> Trying to understand Loom continuation implementation. In following
>> LeakTest, Continuation Object is unreachable after first yield, but
>> its runnable target is not finished yet.
>> There might be some resources allcoated during continuation run (native
>> memory in this test case and free in finally block --- not cleaner way),
>> when continuation object is collected, these resources are not closed or
>> freed.
>>
>>
>> Is it possible to "clean up" a dead continuation which is not finished
>> yet but collecting by GC?
>>
>>
>> Tested with code cloned from github today.
>> javac --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-exports
>> java.base/jdk.internal.misc=ALL-UNNAMED LeakTest.java
>> java --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-exports
>> java.base/jdk.internal.misc=ALL-UNNAMED LeakTest
>> clean continuation
>>
>>
>>
>> import jdk.internal.ref.Cleaner;
>> import jdk.internal.misc.Unsafe;
>> public class LeakTest {
>> private static final Unsafe unsafe = Unsafe.getUnsafe();
>> static ContinuationScope scope = new
>> ContinuationScope("scope");
>> public static void main(String[] args) throws Exception {
>> bar();
>> System.gc();
>> Thread.sleep(1000);
>> System.gc();
>> Thread.sleep(1000);
>> }
>>
>>
>> public static void bar() {
>> Continuation cont = new Continuation(scope,
>> () -> {
>> long mem = 0;
>> try {
>> // open
>> file/socket
>> mem =
>> unsafe.allocateMemory(100);
>>
>> Continuation.yield(scope);
>> } finally {
>>
>> unsafe.freeMemory(mem);
>>
>> System.out.println("release memory");
>> }
>> });
>> Cleaner.create(cont, () -> {
>> System.out.println("clean continuation"); });
>> cont.run();
>> //cont.run();
>> }
>> }
>>
>>
>>
>> Regards
>>
>
More information about the loom-dev
mailing list