Roedy said:
that is how much real ram they consume when they are sitting there
fielding events.
I couldn't believe it. So I consulted the google. And indeed the web
does say 3K. It's even printed on like real paper, so it must be right.
http://java.sun.com/docs/books/performance/1st_edition/html/JPClassLoading.fm.html#24833
Okay, so perhaps it's the old school book trick wherein generations of
authors copying other authors' mistakes. So I shall do my own testing.
Below is a quick & dirty program to create simplistic scalable example
code. And indeed going up to 1000 anonymous inner classes it takes 3K a
class. Unbelievable.
Going higher hit a problem with a laughable hash algorithm in javac. I
patched that with the String code, and reduced my expectations to fit
within the limits of the class file format. 3000 anonymous inner classes
require less memory than just one!!
???
Ah yes, the permanent generation is reluctant to have its garbage
collected (the clue is in the name). One of the EJB servers (BEA?) had a
problem running on Sun's JRE because it could throw OutOfMemoryError
despite having plenty of memory available.Apparently, it used to be the
case that running out of memory for the permanent generation didn't
trigger gc, so you need create transient data to force a collection
(proper details are on the Bug Parade somewhere).
In today's world, System.gc does not appear to collect from the
permanent generation. Naive memory measurements are therefore misleading.
The folk wisdom that inner classes are really expensive is hogwash.
Still, it seems inefficient of the JVM to allocate permanent generation
memory in such a manner.
Tom Hawtin
import java.io.*;
class Gen {
public static void main(String[] args) throws IOException {
final int inners = Integer.getInteger("inners");
File dir = new File("test"+inners);
if (!dir.mkdir()) {
throw new Error("mkdir: "+dir);
}
String pkg = "mylongpackagenameandsomerandompadding";
File pkgDir = new File(dir, pkg);
if (!pkgDir.mkdir()) {
throw new Error("mkdir: "+pkgDir);
}
String cls = "Test"+inners;
Writer out = new BufferedWriter(new FileWriter(new File(
pkgDir, cls+".java"
)));
out.write(
"package "+pkg+";\n"
+"\n"
+"import java.awt.*;\n"
+"import java.awt.event.*;\n"
+"import javax.swing.*;\n"
+"\n"
+"class "+cls+" {\n"
+" public static void main(String[] args) throws Exception {\n"
+" final JButton button = new JButton();\n"
+"\n"
);
for (int ct=0; ct<inners; ++ct) {
out.write(
" button.addActionListener(new ActionListener() {\n"
+" public void actionPerformed(ActionEvent event) {\n"
+" button.setText(\""+ct+"\");\n"
+" }\n"
+" });\n"
);
}
out.write(
"\n"
+" System.gc();\n"
+" Runtime runtime = Runtime.getRuntime();\n"
+" System.out.println(\n"
+" \""+inners+" - \"+\n"
+" \"freeMemory: \" +runtime.freeMemory() +\", \"+\n"
+" \"maxMemory: \" +runtime.maxMemory() +\", \"+\n"
+" \"totalMemory: \"+runtime.totalMemory()+\", \"\n"
+" );\n"
+" Thread.currentThread().join();\n"
+" }\n"
+"}\n"
);
out.close();
}
}