(Preliminary) RFC 7038914: VM could throw uncaught OOME in ReferenceHandler thread

Peter Levart peter.levart at gmail.com
Sat May 4 08:06:09 UTC 2013


On 05/04/2013 01:42 AM, Vitaly Davidovich wrote:
>
> Personally, I think I'd exit the VM in this case. The odds of hitting 
> OOM while allocating TIE and having it be just a very unfortunate 
> transient condition are quite low; most likely, the VM is going to 
> have lots of trouble elsewhere anyway.
>

I thought the purpose of fixing this bug was exactly to support 
un-terminated reference processing in situations where OOME *is* a 
transient condition, and not to take every opportunity to exit the VM 
when OOME is encountered.

> Also, by swallowing the OOM there and continuing makes an assumption 
> that the lock is still in valid/working state; that may be the case 
> today, but I don't know if that's a safe assumption generally.
>

I think It would be a JVM bug if it wasn't so. The construction and 
propagation of InterruptedException should be and is attempted after the 
ownership of the object monitor is re-obtained.

Besides, no OOME will be thrown if the ReferenceHandler thread isn't 
interrupted while there is heap memory shortage, but VM is equally "in 
trouble elsewhere" nevertheless. So I don't think it's 
ReferenceHandler's call to decide when to terminate the VM. It can 
continue with it's purpose unaffected...

Another thing to be considered is what happens when the ReferenceHandler 
thread is stop()-ed while it is executing code inside wait(). In this 
case a ThreadDeath is thrown which should not be caught and ignored. But 
as it appears, the ThreadDeath error object is constructed by the thread 
executing the Thread.stop() method so the OOME can only be thrown in 
that thread and not in the thread being stopped...

To back this claims, I have written the following test:

public class Test extends Thread {

     final Object lock = new Object();

     public Test() {
         super("test");
     }

     static void log(String msg) {
         System.err.println(
             Thread.currentThread().getName() +
             " @ " + new SimpleDateFormat("hh:mm:ss.SSS").format(new 
Date()) +
             ": " + msg
         );
     }

     @Override
     public void run() {
         while (true) {
             synchronized (lock) {
                 try {
                     log("waiting");
                     lock.wait();
                 }
                 catch (InterruptedException ie) {
                     log("interrupted");
                     ie.printStackTrace();
                 }
                 catch (ThreadDeath td) {
                     log("stopped");
                     td.printStackTrace();
                     throw td;
                 }
             }
         }
     }

     public static void main(String[] args) throws Exception {
         Test test = new Test();
         test.start();

         Thread.sleep(1000L);
         synchronized (test.lock) {
             log("interrupting");
             test.interrupt();
             Thread.sleep(1000L);
         }
         log("exited synchronized block 1");

         Thread.sleep(1000L);
         synchronized (test.lock) {
             log("stopping");
             test.stop();
             Thread.sleep(1000L);
         }
         log("exited synchronized block 2");

         test.join();
     }
}


Which produces the following output:

test @ 09:57:53.998: waiting
main @ 09:57:54.974: interrupting
main @ 09:57:55.975: exited synchronized block 1
test @ 09:57:55.975: interrupted
java.lang.InterruptedException: Constructed by test @ 09:57:55.975
     at java.lang.Object.wait(Native Method)
     at java.lang.Object.wait(Object.java:502)
     at test.Test.run(Test.java:36)
test @ 09:57:55.977: waiting
main @ 09:57:56.975: stopping
main @ 09:57:57.976: exited synchronized block 2
test @ 09:57:57.976: stopped
java.lang.ThreadDeath: Constructed by main @ 09:57:56.976
     at java.lang.Thread.stop(Thread.java:815)
     at test.Test.main(Test.java:66)


I also modified the InterruptedException and ThreadDeath no-arg 
constructors to record the thread name and time of construction to get 
this output:

     public InterruptedException() {
         super("Constructed by " + Thread.currentThread().getName() +
               " @ " + new SimpleDateFormat("hh:mm:ss.SSS").format(new 
Date()));
     }


Regards, Peter

> Sent from my phone
>
> On May 3, 2013 3:26 PM, "Peter Levart" <peter.levart at gmail.com 
> <mailto:peter.levart at gmail.com>> wrote:
>
>
>     On 05/03/2013 07:47 PM, Thomas Schatzl wrote:
>
>         Hi,
>
>             Hi Tomas,
>
>             I don't know if this is the case here, but what if the
>             ReferenceHandler thread is interrupted while wait()-ing
>             and the
>             construction of InterruptedException triggers OOME?
>
>         I am sure this is the case - previously I thought
>         InterruptedException
>         is a preallocated exception like others.
>         ObjectMonitor::wait() may throw it, by creating new
>         InterruptedException
>         instances.
>
>         Thanks!
>
>         Now that we've found the very likely cause, what to do about it?
>
>
>     Maybe just ignore it since if it happens during wait(), the cause
>     is supposed to be interrupted thread and the InterruptedException
>     that was to be thrown would be ignored too:
>
>                             try {
>                                 lock.wait();
>                             } catch (InterruptedException |
>     OutOfMemoryError x) { }
>
>     Regards, Peter
>
>         The current state of silently crashing the reference handler
>         thread is
>         unsatisfying imo as it leads to very hard to find problems.
>
>         The options I see all involve catching this (or any other OOME
>         caused by
>         other means like the test program) and either recovering as
>         much as
>         possible or exiting the VM (like in the sun.misc.Cleaner
>         handling).
>
>         Any other suggestions?
>
>         Thanks,
>         Thomas
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/hotspot-gc-dev/attachments/20130504/070aaec7/attachment.htm>


More information about the hotspot-gc-dev mailing list