Community
Participate
Working Groups
An OutOfMemoryError occurs when compiling a class with deeply-nested try-catch blocks. This is probably best reproduced using the batch compiler from the command line. You can import the class below into a Java project if you wish, but if you do, you should expect to be stuck at "Building workspace: (1%)" for a while, with the CPU pegged, and eventually having to shut down your workbench. I ran the compiler thus: java -classpath c:/eclipse/plugins/org.eclipse.jdt.core_3.1.0.jar org.eclipse.jdt.internal.compiler.batch.Main ExcNested.java Trying to compile the class with the batch compiler results in: Internal compiler error java.lang.OutOfMemoryError: Java heap space Upping the heap to -Xmx400m doesn't help, but it does take longer to fail. I tried this with both 1.4 & 1.5 VMs and with both 3.0.2 and 3.1.0 versions of jdtcore. Javac 1.4 & 1.5 and Jikes 1.21 compile this with no trouble. /* This program is derived from test.OSF.valid.lang.ExcNested, which bears the * following notices: * * Copyright (c) 1995, 1996 * Open Software Foundation, Inc. * * OSF DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED, * WITH RESPECT TO THIS SOFTWARE INCLUDING, WITHOUT LIMITATION, * ANY WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN CONTRACT, TORT * INCLUDING NEGLIGENCE, OR OTHER LEGAL THEORY ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* * This file is part of an OSF RI software distribution. This software is * distributed under the terms of a free license for non-commercial use. * * You should have received a copy of those terms along with this file. * Please see file COPYRIGHT. * * If not, please write to: OSF RI, 2 Av. de Vignate, 38610 Gieres, France */ public class ExcNested { public ExcNested() {} static int except_count; static boolean test_result = true; static Throwable all_except[] = { new AbstractMethodError(), // 0 new ArithmeticException(), // 1 new ArrayIndexOutOfBoundsException(), // 2 new ArrayStoreException(), // 3 new ClassCastException(), // 4 new ClassCircularityError(), // 5 new ClassFormatError(), // 6 new ClassNotFoundException(), // 7 new CloneNotSupportedException(), // 8 new Error(), // 9 new Exception(), // 10 new IllegalAccessError(), // 11 new IllegalAccessException(), // 12 new IllegalArgumentException(), // 13 new IllegalMonitorStateException(), // 14 new IllegalThreadStateException(), // 15 new IncompatibleClassChangeError(), // 16 new IndexOutOfBoundsException(), // 17 new InstantiationError(), // 18 new InstantiationException(), // 19 new InternalError(), // 20 new InterruptedException(), // 21 new LinkageError(), // 22 new NegativeArraySizeException(), // 23 new NoClassDefFoundError(), // 24 new NoSuchFieldError(), // 25 new NoSuchMethodError(), // 26 new NoSuchMethodException(), // 27 new NullPointerException(), // 28 new NumberFormatException(), // 29 new OutOfMemoryError(), // 30 new StackOverflowError(), // 31 new RuntimeException(), // 32 new SecurityException(), // 33 new StringIndexOutOfBoundsException(), // 34 new ThreadDeath(), // 35 new UnknownError(), // 36 new UnsatisfiedLinkError(), // 37 new VerifyError(), // 38 }; private static void check_except(int i) throws Throwable { if (except_count != i) { System.out.println("Error "+except_count+" != "+i+";"); test_result=false; } throw all_except[++except_count]; } public static void main(String[] args) throws Throwable { try { except_count = 0; throw all_except[except_count]; } catch (AbstractMethodError e0) { try { check_except(0); } catch (ArithmeticException e1) { try { check_except(1); } catch (ArrayIndexOutOfBoundsException e2) { try { check_except(2); } catch (ArrayStoreException e3) { try { check_except(3); } catch (ClassCastException e4) { try { check_except(4); } catch (ClassCircularityError e5) { try { check_except(5); } catch (ClassFormatError e6) { try { check_except(6); } catch (ClassNotFoundException e7) { try { check_except(7); } catch (CloneNotSupportedException e8) { try { check_except(8); } catch (Error e9) { try { check_except(9); } catch (Exception e10) { try { check_except(10); } catch (IllegalAccessError e11) { try { check_except(11); } catch (IllegalAccessException e12) { try { check_except(12); } catch (IllegalArgumentException e13) { try { check_except(13); } catch (IllegalMonitorStateException e14) { try { check_except(14); } catch (IllegalThreadStateException e15) { try { check_except(15); } catch (IncompatibleClassChangeError e16) { try { check_except(16); } catch (IndexOutOfBoundsException e17) { try { check_except(17); } catch (InstantiationError e18) { try { check_except(18); } catch (InstantiationException e19) { try { check_except(19); } catch (InternalError e20) { try { check_except(20); } catch (InterruptedException e21) { try { check_except(21); } catch (LinkageError e22) { try { check_except(22); } catch (NegativeArraySizeException e23) { try { check_except(23); } catch (NoClassDefFoundError e24) { try { check_except(24); } catch (NoSuchFieldError e25) { try { check_except(25); } catch (NoSuchMethodError e26) { try { check_except(26); } catch (NoSuchMethodException e27) { try { check_except(27); } catch (NullPointerException e28) { try { check_except (28); } catch (NumberFormatException e29) { try { check_except (29); } catch (OutOfMemoryError e30) { try { check_except (30); } catch (StackOverflowError e31) { try { check_except(31); } catch (RuntimeException e32) { try { check_except(32); } catch (SecurityException e33) { try { check_except(33); } catch (StringIndexOutOfBoundsException e34) { try { check_except(34); } catch (ThreadDeath e35) { try { check_except(35); } catch (UnknownError e36) { try { check_except(36); } catch (UnsatisfiedLinkError e37) { try { check_except(37); } catch (VerifyError e38) { ++except_count; }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} // Check that all exceptions have been raised. System.out.println(test_result & (except_count == all_except.length)); } }
The problem comes from the code generation. I am investigating.
The problem comes from the forward reference count inside the labels.
Created attachment 29248 [details] Proposed fix
In practice, forward refs are generally sorted already (per construction). Thus I suspect Arrays.sort(int[],...) is not optimized for this scenario. Also note that individual additions of forward refs is not checking for duplicates (only checked when adding all refs from other label). Once fixed, should be backported to 3.1, and likely to 3.0.
Created attachment 29255 [details] Variation on the patch which isn't performing any sorting It does check for dup addition of single forward refs. If array size remains small , the non sorting may not be an issue.
Created attachment 29265 [details] New proposal
Created attachment 29267 [details] New proposal This will be released as soon as M3 is declared.
Backported to 3.1 maintenance stream. Added regression test org.eclipse.jdt.core.tests.compiler.regression.TryStatementTest.test031
Backported to 3.0 maintenance stream. Added regression test org.eclipse.jdt.core.tests.compiler.regression.TryStatementTest.test026
Fixed and released in HEAD. Added regression test org.eclipse.jdt.core.tests.compiler.regression.TryStatementTest.test032
Verified for 3.2 M4 using build I20051212-0010
Reopen for 3.1.2 verification
We also need to verify that's this bug fix is in R3_1_maintenance stream as well before 3.1.2 delivery...
Verified for 3.1.2 using build M20060109-1200.
Verified for 3.1.2 using build M20060109-1200 (maxime)