Unreleased Resource: Database 未释放资源:数据库java
程序可能没法成功释放某一项系统资源。数据库
程序可能没法成功释放某一项系统资源。 资源泄露至少有两种常见的缘由:
- 错误情况及其余异常状况。
- 未明确程序的哪一部份负责释放资源。
大部分 Unreleased Resource 问题只会致使通常的软件可靠性问题, 但若是攻击者可以故意触发资源泄漏,该攻击者就有可能经过耗尽资源池的方式发起 denial of service 攻
击。
例 1: 下面的方法毫不会关闭它所打开的文件句柄。 FileInputStream 中的 finalize() 方法最终会调用 close(),但没法保证它调用 finalize() 方法的时间。 在繁忙的环境中,这会致使 JVM 用尽它全部的文件句柄。网络
private void processFile(String fName) throws FileNotFoundException, IOException { FileInputStream fis = new FileInputStream(fName); int sz; byte[] byteArray = new byte[BLOCK_SIZE]; while ((sz = fis.read(byteArray)) != -1) { processBytes(byteArray, sz); } }
例 2: 在正常条件下,如下代码会执行数据库查询指令,处理数据库返回的结果,并关闭已分配的指令对象。 但若是在执行 SQL 或是处理结果时发生异常,指令对象将不会关闭。 若是这种状况频繁出现,数据库将用完全部可用的指针,且不能再执行任何 SQL 查询。函数
Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(CXN_SQL); harvestResults(rs); stmt.close();
1.毫不要依赖 finalize() 回收资源。 为了使对象的 Finalize() 方法能被调用,垃圾收集器必须确认对象符合垃圾回收的条件。 可是垃圾收集器只有在 JVM 内存太小时才会使用。所以,没法保证什么时候可以调用该对象的 finalize() 方法。 垃圾收集器最终运行时,可能出现这样的状况,即在短期内回收大量的资源,这种状况会致使“突发”性能,并下降整体系统经过量。 随着系统负载的增长,这种影响会愈来愈明显。 最后, 若是某一资源回收操做被挂起(例如该操做须要经过网络访问数据库),那么执行 finalize() 方法的线程也将被挂起。 2. 在 finally 代码段中释放资源。 例 2 中的代码可按如下方式改写:性能
public void execCxnSql(Connection conn) { Statement stmt; try { stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(CXN_SQL); ... } finally { if (stmt != null) { safeClose(stmt); } } } public static void safeClose(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { log(e); } } }
以上方案使用了一个助手函数,用以记录在尝试关闭指令时可能产生的异常。 该助手函数大约会在须要关闭指令时从新使用。 一样, execCxnSql 方法不会将 stmt 对象预置为空。 而是进行检查,以确保调用safeClose() 以前, stmt 不是 null。 若是没有检查 null, Java 编译器会报告 stmt 可能没有进行初始化。 编译器作出这一判断源于 Java 能够检测未初始化的变量。 若是用一种更加复杂的方法将 stmt 初始化为 null,那么 Java 编译器就没法检测 stmt 是否已被初始化。线程