zoukankan      html  css  js  c++  java
  • Stream 未释放系统资源问题处理

    Unreleased Resource: Streams 

    Abstract

    程序可能无法成功释放某一项系统资源。

    Explanation

    程序可能无法成功释放某一项系统资源。 资源泄露至少有两种常见的原因: - 错误状况及其他异常情况。
    - 未明确程序的哪一部份负责释放资源。 大部分 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();

    Recommendation

    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 是否已被初始化。
    Copyright © 2021 Shinoburedo
  • 相关阅读:
    【SPI】浅谈JDK中SPI技术
    【MySQL8.0.18】阿里云服务器上搭建MySQL数据库
    【JDK13】阿里云服务器安装JDK13
    小型个人博客搭建之数据库设计
    【算法题】CCF CSP第三题练习(更新中)
    【算法题】CCF CSP第一题练习
    【嵌入式】KEIL4和KEIL5合并
    【ROS】安装ubuntu18.04+ros-melodic
    Notepad++配置python之NppExec
    vi一般指令命令行
  • 原文地址:https://www.cnblogs.com/xiaro115/p/14764535.html
Copyright © 2011-2022 走看看