Dead Continuation cause resource leak?
Alex Otenko
oleksandr.otenko at gmail.com
Fri May 29 06:39:09 UTC 2020
Thanks, that's a very good argument.
So in vanilla java we can speak of A() being nonblocking, in which case we
can speak of B() being eventually reachable. How would you describe the
property of A() that preserves semantics of return value and exception
delivery? That is, hands off control to continuations correctly?
Alex
On Fri, 29 May 2020, 01:05 Ron Pressler, <ron.pressler at oracle.com> wrote:
>
> I’m not sure I follow. Suppose you have the following code:
>
> try {
> A();
> } finally {
> B();
> }
>
> Then Java makes no guarantees that, if you ever enter A, then B is
> eventually
> executed. For example, A can sleep forever, or the kernel scheduler could
> starve
> the thread.
>
> In fact, Continuation.run can be implemented in the mainline JDK by
> spawning a
> new thread and synchronizing with it. What is semantically different would
> be
> matters of thread identity. An example relevant to your situation is that
> two
> methods could make concurrent progress while both running on the same
> thread.
> The converse would be that the following code,
>
> var t1 = Thread.currentThread();
> A();
> var t2 = Thread.currentThread();
>
> would guarantee that t1 == t2 in the mainline JDK but not in Loom. This
> would
> probably be even more troublesome than your example, which is one reason
> why
> we're not exposing continuations at this time. If continuations are ever
> exposed, their behaviour will clearly become a part of the relevant Java
> specifications.
>
> These issues do not arise with virtual threads.
>
> - Ron
>
>
>
> On 28 May 2020 at 23:38:59, Alex Otenko (oleksandr.otenko at gmail.com
> (mailto:oleksandr.otenko at gmail.com)) wrote:
>
> > When you write an Iterator, you are conscious of writing an Iterator.
> When you are writing a consumer, you expect plain java semantics: combining
> pieces of computation that do terminate, produces a program that
> terminates.
> >
> > If Continuation is not going to be public, it's less of a concern.
> Although the question of verification of which parts of jls are not
> violated is interesting.
> >
> > Alex
> > On Thu, 28 May 2020, 17:32 Ron Pressler, wrote:
> > > What happens if you write an iterator that only performs cleanup when
> it
> > > terminates, but then encounters an exception in the middle of
> iteration? How
> > > does the consumer know if some cleanup has been missed?
> > >
> > > Anyway, just to make clear, continuations will *not* be exposed as a
> public
> > > class, at least not at first. The current public class will be made
> internal.
> > >
> > > — Ron
> > >
> > >
> > > On 28 May 2020 at 15:52:01, Alex Otenko (oleksandr.otenko at gmail.com
> (mailto:oleksandr.otenko at gmail.com)) wrote:
> > >
> > > > 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(https://urldefense.com/v3/__https://github.com/forax/loom-fiber/blob/master/src/main/java/fr.umlv.loom/fr/umlv/loom/Generators.java*L74__;Iw!!GqivPVa7Brio!NU6HHPPmB_c4ddOo6HK_BCS1olDVhg-f-WX1PBEIkCnQCxvU2Ixlw1rWNLIpQas1eA$)
>
> > > >
> > > > 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, 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(mailto: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, 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(mailto:
> 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