2007-07-16 01:03:02 +00:00
|
|
|
public class GC {
|
2010-09-17 01:43:27 +00:00
|
|
|
private static final Integer cache[] = new Integer[100];
|
|
|
|
private static final Integer MAX_INT_OBJ = new Integer(Integer.MAX_VALUE);
|
|
|
|
|
|
|
|
private static Integer valueOf(int i) {
|
|
|
|
try {
|
|
|
|
return cache[i];
|
|
|
|
} catch (ArrayIndexOutOfBoundsException e) {
|
|
|
|
return (i == Integer.MAX_VALUE) ? MAX_INT_OBJ : new Integer(i);
|
|
|
|
}
|
|
|
|
}
|
2007-06-21 01:37:43 +00:00
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
private static void small() {
|
2007-06-21 22:51:13 +00:00
|
|
|
for (int i = 0; i < 1024; ++i) {
|
|
|
|
byte[] a = new byte[4 * 1024];
|
|
|
|
}
|
2007-06-22 23:17:13 +00:00
|
|
|
}
|
2007-06-21 22:51:13 +00:00
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
private static void medium() {
|
2007-06-22 22:47:57 +00:00
|
|
|
for (int i = 0; i < 8; ++i) {
|
2007-06-21 22:51:13 +00:00
|
|
|
Object[] array = new Object[32];
|
|
|
|
for (int j = 0; j < 32; ++j) {
|
|
|
|
array[j] = new byte[32 * 1024];
|
|
|
|
}
|
2007-06-21 18:35:24 +00:00
|
|
|
}
|
2007-06-22 23:17:13 +00:00
|
|
|
}
|
2007-06-22 22:47:57 +00:00
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
private static void large() {
|
2007-06-22 22:47:57 +00:00
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
|
|
byte[] a = new byte[16 * 1024 * 1024];
|
|
|
|
}
|
2007-10-28 01:54:30 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
|
|
byte[] a = new byte[16 * 1024 * 1024];
|
|
|
|
for (int j = 0; j < 32; ++j) {
|
|
|
|
byte[] b = new byte[32 * 1024];
|
|
|
|
}
|
|
|
|
}
|
2007-06-21 01:37:43 +00:00
|
|
|
}
|
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
private static void stackMap1(boolean predicate) {
|
2008-01-06 19:20:30 +00:00
|
|
|
if (predicate) {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
System.gc();
|
2008-01-06 19:20:30 +00:00
|
|
|
}
|
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
private static void stackMap2(boolean predicate) {
|
2008-01-06 19:20:30 +00:00
|
|
|
if (predicate) {
|
|
|
|
int a = 42;
|
|
|
|
} else {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
System.gc();
|
2008-01-06 19:20:30 +00:00
|
|
|
}
|
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
private static void stackMap3(boolean predicate) {
|
2008-01-07 21:32:41 +00:00
|
|
|
if (predicate) {
|
|
|
|
Object a = null;
|
|
|
|
} else {
|
|
|
|
int a = 42;
|
|
|
|
}
|
|
|
|
|
|
|
|
System.gc();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void stackMap4(boolean predicate) {
|
2008-01-06 19:20:30 +00:00
|
|
|
int i = 2;
|
|
|
|
if (predicate) {
|
|
|
|
Object a = null;
|
|
|
|
} else {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2008-01-07 16:01:35 +00:00
|
|
|
System.gc();
|
2008-01-06 19:20:30 +00:00
|
|
|
int a = 42;
|
|
|
|
-- i;
|
|
|
|
} while (i >= 0);
|
|
|
|
}
|
|
|
|
|
2008-01-07 21:32:41 +00:00
|
|
|
private static void noop() { }
|
|
|
|
|
|
|
|
private static void stackMap5(boolean predicate) {
|
|
|
|
if (predicate) {
|
|
|
|
noop();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (predicate) {
|
|
|
|
noop();
|
|
|
|
} else {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
System.gc();
|
|
|
|
}
|
|
|
|
|
2008-03-05 21:44:17 +00:00
|
|
|
private static void stackMap6(boolean predicate) {
|
|
|
|
if (predicate) {
|
|
|
|
int a = 42;
|
|
|
|
} else {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (predicate) {
|
|
|
|
noop();
|
|
|
|
} else {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
noop();
|
|
|
|
System.gc();
|
|
|
|
}
|
|
|
|
|
fix stack frame mapping code for exception handlers
Previously, the stack frame mapping code (responsible for statically
calculating the map of GC roots for a method's stack frame during JIT
compilation) would assume that the map of GC roots on entry to an
exception handler is the same as on entry to the "try" block which the
handler is attached to. Technically, this is true, but the algorithm
we use does not consider whether a local variable is still "live"
(i.e. will be read later) when calculating the map - only whether we
can expect to find a reference there via normal (non-exceptional)
control flow. This can backfire if, within a "try" block, the stack
location which held an object reference on entry to the block gets
overwritten with a non-reference (i.e. a primitive). If an exception
is later thrown from such a block, we might end up trying to treat
that non-reference as a reference during GC, which will crash the VM.
The ideal way to fix this is to calculate the true interval for which
each value is live and use that to produce the stack frame maps. This
would provide the added benefit of ensuring that the garbage collector
does not visit references which, although still present on the stack,
will not be used again.
However, this commit uses the less invasive strategy of ANDing
together the root maps at each GC point within a "try" block and using
the result as the map on entry to the corresponding exception
handler(s). This should give us safe, if not optimal, results. Later
on, we can refine it as described above.
2010-02-05 01:03:32 +00:00
|
|
|
private static void stackMap7(boolean predicate) {
|
|
|
|
try {
|
|
|
|
if (predicate) {
|
|
|
|
Object a = null;
|
|
|
|
} else {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
int a = 42;
|
|
|
|
throw new DummyException();
|
|
|
|
} finally {
|
|
|
|
System.gc();
|
|
|
|
}
|
|
|
|
} catch (DummyException e) {
|
|
|
|
e.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void stackMap8(boolean predicate) {
|
|
|
|
try {
|
|
|
|
Object x = new Object();
|
|
|
|
if (predicate) {
|
|
|
|
Object a = null;
|
|
|
|
} else {
|
|
|
|
Object a = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
int a = 42;
|
|
|
|
throw new DummyException();
|
|
|
|
} finally {
|
|
|
|
System.gc();
|
|
|
|
x.toString();
|
|
|
|
}
|
|
|
|
} catch (DummyException e) {
|
|
|
|
e.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
public static void main(String[] args) {
|
2010-09-17 01:43:27 +00:00
|
|
|
valueOf(1000);
|
|
|
|
|
2008-01-02 01:09:05 +00:00
|
|
|
Object[] array = new Object[1024 * 1024];
|
|
|
|
array[0] = new Object();
|
|
|
|
|
2007-12-23 18:48:22 +00:00
|
|
|
small();
|
2008-01-02 01:09:05 +00:00
|
|
|
|
|
|
|
array[1] = new Object();
|
|
|
|
|
2007-06-22 23:17:13 +00:00
|
|
|
medium();
|
2008-01-02 01:09:05 +00:00
|
|
|
|
|
|
|
array[2] = new Object();
|
|
|
|
|
2007-12-23 18:48:22 +00:00
|
|
|
large();
|
2008-01-02 01:09:05 +00:00
|
|
|
|
|
|
|
array[0].toString();
|
|
|
|
array[1].toString();
|
|
|
|
array[2].toString();
|
2008-01-06 19:20:30 +00:00
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
stackMap1(true);
|
|
|
|
stackMap1(false);
|
2008-01-06 19:20:30 +00:00
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
stackMap2(true);
|
|
|
|
stackMap2(false);
|
2008-01-06 19:20:30 +00:00
|
|
|
|
2008-01-07 16:01:35 +00:00
|
|
|
stackMap3(true);
|
|
|
|
stackMap3(false);
|
2008-01-07 21:32:41 +00:00
|
|
|
|
|
|
|
stackMap4(true);
|
|
|
|
stackMap4(false);
|
|
|
|
|
|
|
|
stackMap5(true);
|
|
|
|
stackMap5(false);
|
2008-03-05 21:44:17 +00:00
|
|
|
|
|
|
|
stackMap6(true);
|
|
|
|
stackMap6(false);
|
fix stack frame mapping code for exception handlers
Previously, the stack frame mapping code (responsible for statically
calculating the map of GC roots for a method's stack frame during JIT
compilation) would assume that the map of GC roots on entry to an
exception handler is the same as on entry to the "try" block which the
handler is attached to. Technically, this is true, but the algorithm
we use does not consider whether a local variable is still "live"
(i.e. will be read later) when calculating the map - only whether we
can expect to find a reference there via normal (non-exceptional)
control flow. This can backfire if, within a "try" block, the stack
location which held an object reference on entry to the block gets
overwritten with a non-reference (i.e. a primitive). If an exception
is later thrown from such a block, we might end up trying to treat
that non-reference as a reference during GC, which will crash the VM.
The ideal way to fix this is to calculate the true interval for which
each value is live and use that to produce the stack frame maps. This
would provide the added benefit of ensuring that the garbage collector
does not visit references which, although still present on the stack,
will not be used again.
However, this commit uses the less invasive strategy of ANDing
together the root maps at each GC point within a "try" block and using
the result as the map on entry to the corresponding exception
handler(s). This should give us safe, if not optimal, results. Later
on, we can refine it as described above.
2010-02-05 01:03:32 +00:00
|
|
|
|
|
|
|
stackMap7(true);
|
|
|
|
stackMap7(false);
|
|
|
|
|
|
|
|
stackMap8(true);
|
|
|
|
stackMap8(false);
|
2007-06-22 23:17:13 +00:00
|
|
|
}
|
|
|
|
|
fix stack frame mapping code for exception handlers
Previously, the stack frame mapping code (responsible for statically
calculating the map of GC roots for a method's stack frame during JIT
compilation) would assume that the map of GC roots on entry to an
exception handler is the same as on entry to the "try" block which the
handler is attached to. Technically, this is true, but the algorithm
we use does not consider whether a local variable is still "live"
(i.e. will be read later) when calculating the map - only whether we
can expect to find a reference there via normal (non-exceptional)
control flow. This can backfire if, within a "try" block, the stack
location which held an object reference on entry to the block gets
overwritten with a non-reference (i.e. a primitive). If an exception
is later thrown from such a block, we might end up trying to treat
that non-reference as a reference during GC, which will crash the VM.
The ideal way to fix this is to calculate the true interval for which
each value is live and use that to produce the stack frame maps. This
would provide the added benefit of ensuring that the garbage collector
does not visit references which, although still present on the stack,
will not be used again.
However, this commit uses the less invasive strategy of ANDing
together the root maps at each GC point within a "try" block and using
the result as the map on entry to the corresponding exception
handler(s). This should give us safe, if not optimal, results. Later
on, we can refine it as described above.
2010-02-05 01:03:32 +00:00
|
|
|
private static class DummyException extends RuntimeException { }
|
2007-06-21 01:37:43 +00:00
|
|
|
}
|