Can you please explain, where the instances of Exception or it's ch开发者_Go百科ildren are allocated in memory? Is it heap or stack, or something else?
Thanks!
For most JVM's all Object are created on the heap and Exception is not an exception. ;)
A JVM could allocate objects on the stack using Escape Analysis, however this is usually limited to objects which are used only in one method and not returned. i.e. it is highly unlikely that Exceptions would be a good candidate.
Something which is special about the way Throwables (incl Exception) are created on many JVMs is that the stack trace elements are not created until they are needed. This is because most of the time they are not needed and they are expensive to create. However the information to create the stack trace is retained some where by the JVM and associated with the Throwable, but it is not visible to the debugger or reflection.
public static void main(String... args) {
Throwable t = new Throwable("here");
System.out.println("Throwable before getStackTrace()");
shallowDump(t);
System.out.println("\nThrowable after getStackTrace()");
t.getStackTrace();
shallowDump(t);
}
private static void shallowDump(Object pojo) {
for (Field f : pojo.getClass().getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())) continue;
f.setAccessible(true);
Object o;
try {
o = f.get(pojo);
if (o == pojo)
o = "{self}";
if (o instanceof Object[])
o = "Array of "+(o.getClass().getComponentType());
} catch (Exception e) {
o = e;
}
System.out.println(f.getName() + ": " + o);
}
}
prints
Throwable before getStackTrace()
detailMessage: here
cause: {self}
stackTrace: null
Throwable after getStackTrace()
detailMessage: here
cause: {self}
stackTrace: Array of class java.lang.StackTraceElement
So the question arises, where is the information which used to create the StackTraceElement retained. Looking at the code, native methods are used to access the information. There is a mysterious field called backtrace
which you cannot see using reflection.
System.gc();
for (int i = 0; i < 5; i++) {
Throwable[] ts = new Throwable[10000];
long free = Runtime.getRuntime().freeMemory();
for (int j = 0; j < ts.length; j++)
ts[j] = new Throwable();
long used = free - Runtime.getRuntime().freeMemory();
System.out.printf("Average Throwable size was %,d%n", used / ts.length);
}
System.gc();
for (int i = 0; i < 5; i++) {
Throwable[] ts = new Throwable[10000];
long free = Runtime.getRuntime().freeMemory();
for (int j = 0; j < ts.length; j++)
ts[j] = Throwable.class.newInstance();
long used = free - Runtime.getRuntime().freeMemory();
System.out.printf("Average Throwable.class.newInstance() size was %,d%n", used / ts.length);
}
This gets the size of a Throwable created in the current method and a Throwable created in a deeper method via reflection (which has a deeper stack)
Average Throwable size was 302
Average Throwable size was 302
Average Throwable size was 302
Average Throwable size was 302
Average Throwable size was 302
Average Throwable.class.newInstance() size was 247
Average Throwable.class.newInstance() size was 296
Average Throwable.class.newInstance() size was 296
Average Throwable.class.newInstance() size was 296
Average Throwable.class.newInstance() size was 296
The size of a Throwable is much larger than you might expect from the fields it has. One can assume some additional information is being stored on the heap to help this class, however, is all the information were stored in the Throwable object , you expect the second type of Throwable to be larger.
All objects in Java by default allocated in a heap. You may specially say that about Exception instances, cause they're commonly passed to caller method, thus there is no way they can be on a stack.
They are created on the heap, but why does this matter?
Exception
s (and all Throwable
s) are just like any other kind of Java object. Therefore, they will appear in the heap. As MusiKk pointed out, the stack can only hold primitive values or object references.
精彩评论