calcite适配内部通过janino将字符串动态编译为类,加载到jvm使用。通过添加-XX:+TraceClassLoading项,控制台不停刷Loaded Baz from file:/E:/.m2/reposiory/org/codehaus/janino/janino/2.7.6/janino-2.7.6.jar。
希望通过卸载之前加载的Baz类来释放PermGen Space,在jvm启动项添加CMSPermGenSweepingEnabled和CMSClassUnloadingEnabled后,通过jconsole观察,没有类被卸载,当前加载类数量仍然呈线性持续攀升。
故发此贴,求大牛指点。
方法区溢出也是一种常见的内存溢出异常,一个类要被垃圾收集器回收掉,判定条件是比较苛刻的。在经常动态生成大量Class的应用中,需要特别注意类的回收状况
这个问题存在于1.17之前,在1.17修复了这个问题,具体原因:CalciteStatement重写了父类的
close_()
父类AvaticaStatement:
protected void close_() {
if (!closed) {
closed = true;
if (openResultSet != null) {
AvaticaResultSet c = openResultSet;
openResultSet = null;
c.close();
}
try {
// inform the server to close the resource
connection.meta.closeStatement(handle);
} finally {
// make sure we don't leak on our side
connection.statementMap.remove(handle.id);
connection.flagMap.remove(handle.id);
}
// If onStatementClose throws, this method will throw an exception (later
// converted to SQLException), but this statement still gets closed.
connection.driver.handler.onStatementClose(this);
}
}
CalciteStatement重写后:
@Override protected void close_() {
if (!closed) {
closed = true;
final CalciteConnectionImpl connection1 =
(CalciteConnectionImpl) connection;
connection1.server.removeStatement(handle);
if (openResultSet != null) {
AvaticaResultSet c = openResultSet;
openResultSet = null;
c.close();
}
// If onStatementClose throws, this method will throw an exception (later
// converted to SQLException), but this statement still gets closed.
connection1.getDriver().handler.onStatementClose(this);
}
}
方法,导致
connection.statementMap
connection.flagMap
中的资源没有释放,statementMap存放的为<Integer, AvaticaStatement>
,也就是statement没有关闭,同样与它bind的Baz对象没有释放,
最终会导致内存泄露