Do coroutines safely prevent memory leaks? I’d ass...
# coroutines
m
Do coroutines safely prevent memory leaks? I’d assume so, but if that’s the case I think that it would be a good idea to state it more explicitly in the documentation.
In this example, would the activity be leaked after leaving it?
g
Of course it will leak
you cannot cancel non-cancellable operation
and yeah, coroutines did everything what is possible in this case to avoid leak. But because you use blocking code which impossible to cancel there is no way to avoid leak
m
I agree, the inner coroutine started by
withContext
can’t be cancelled. But the coroutine started by
launch
can.
Since it’s just being suspended by waiting for the result from
withContext
g
Yes, and it will be cancelled, but because code is blocking, there is no way to return and cleanup
m
There is definitely a way, it’s not impossible. The continuation referenced by the
withContext
coroutine would just have to be null, since it’s cancelled anyways.
g
But in this case coroutine will leak
also what if you want to cleanup, like use try/catch
I may be wrong of course probably better to ask @elizarov
but not sure that there is a way to make such badly written code safe without breaking contract
m
Sure, thanks for your input 🙂 You have a good point with the cleanup
g
just to clarify I mean:
Copy code
launch {
try {  
            val message = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
                Thread.sleep(Long.MAX_VALUE)
                "Hello World!"
            }
        }
} finally {
   //do some required operation in any case
}
}
👍 1
e
I fully support what @gildor says. We cannot just “abandon” coroutines on cancellation, because they might need to do cleanup, so there is no way to prevent leaks if you have non-cancellable operation. Coroutines are doing their best to avoid leaks, but cancellation is cooperative, so you have to also do your part — make sure all your operations are cancelable.
👍 1
r
Please correct me if I am wrong Is the Reason being there is leak because withContext was totally started with different Context. So it's independent of launch scope. Therefore even if launch is cancelled but withContext work is still in progress.
m
@Rohan Maity No,
withContext
inherits the parent job from
launch
, so it will receive the cancellation. The issue is that the cancellation won’t do anything because the coroutine doesn’t handle it. This coroutine will therefore continue running, and will keep the reference to the activity through its continuation.
r
It is said "you can't cancel the non cancellable operation". So what part makes the non cancellable operation?
g
Thread.sleep is blocking operation that cannot be cancelled
💯 3
s
I understand the routine inside
withContext
does not cancel and keeps running. But this block of code does not have a reference to anything in the Activity. This block of code doesn't leak. But the
launch
has a call to
this@CoroutineActivity.findViewById
which can leak the Activity. Does a coroutine not cancel if one of its child-coroutines are not cancelled? Could a cancel request interrupt a running Thread?
g
There is no way to interrupt threads on JVM starting from Java 1.2 (or even 1.1)
stop method just doesn't work
There is interrupt method which is also just a flag to use it for cancellable operations in a thread
Funny, you actually can cancel Thread.sleep
But for all other blocking calls it's usually doesn't work
Also interrupting thread is not want you want on a shared thread pool
r
So in this case Thread.sleep is not blocking ?
g
Is blocking, it's just implemented in a way when it throws InterruptException in case of thread interruption
But Interrupting is probably a bad idea as I said, but also we are not talking probably about thread sleep, it's just an example
v
Could a cancel request interrupt a running Thread?
No. Interruptions are asynchronous by its nature and can be delivered to the “wrong” coroutine. E.g. what if you run he following
Copy code
val job = launch(singleThreadDispatcher) {
   Thread.sleep(1)
}

val job2 = launch(singleThreadDispatcher) {
  ...
}

job.cancel() // let's assume "cancel" interrupts thread where coroutine is running
How can you guarantee that interrupt will be delivered while
job
is executing, not
job2
?
not talking about the fact, that most of the code does not handle interruptions properly
s
@gildor Ah, that is what I was seeing, that Thread.sleep is interrupted (not cancelled). This means that a cancellation requests one with a thread-interrupt. Even some socket operations are interruptable. But let's assume, the thread is truly blocking and can't be interrupted. Does
launch
fail to be cancelled because its child-routine in
withContext
is never cancelled?
r
Yeah we are not talking about Threads One more thing as Thread.sleep is blocking part . So it keeps running withContext . As withContext is launch it will keep it alive also message is also used in findViewById?
@Vsevolod Tolstopyatov [JB] that was very good example . Thanks for clearing that .
g
Launch is not failed to be cancelled, it's actually cancelled, but to return launch must wait for child cancellation too
👍 1
s
Thanks! In short, parent routine's cancellation must wait for all its child-routines' cancellations. Is this correct?
g
yes
👍 1