Calcite使用: JVM PermGen持续上涨直到OOM PermGen Space

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对象没有释放,
最终会导致内存泄露