各位前辈,你们好,最近公司项目遇到了头疼的问题,web应用运行后一天要重新启动服务6次~8次,原因都是webLogic报内存不足。于是我开始进入优化阶段,在代码中发现了如下代码体,请问是否需要改写?byte[] byteGz = .....
Map<String,BufferedInputStream> map = new HashMap<String,new BufferedInputStream>();
map.put("a",new BufferedInputStream(new ByteArrayInputStream(byteGz)));
...
之后的逻辑会调用void createPdf(Map<String,BufferedInputStream> map)方法生成pdf文件存放到数据库中,BufferedInputStream流对象由于没有任何指向,因此始终没有代码实现流的关闭。
请问:
1、这种代码实现的方式会不会造成流对象无法关闭从而造成内存不足?
2、如果createPdf()方法引发异常的时候会不会造成流对象无法关闭从而造成内存不足?
我也非常清楚这样的写法不可取,最起码应该在finally块中释放使用的流,有可能是由于项目组开发初期io流操作知识欠缺,造成项目中大量的代码都是这样实现的,希望能够指点迷津,代码量太大,而且时间比较紧,如果内存会被自动回收,那么当前暂时就不对这块做改动。

解决方案 »

  1.   

    这个没有试过。大量的文件流不关闭的话的确会引发问题的吧
    不过 JAVA有自动回收机制 也就是说在回收之前,内存的容量不被占满应该没有问题。(但是JAVA的回收机制是相当不确定的。具有不稳定性,就是你不知道他什么时候会回收垃圾)
    生成PDF放数据库是什么意思呢
      

  2.   


    由于生成的pdf不可任意复制或者下载,因此要把生成的pdf存入数据库的blob字段中
      

  3.   

    此外,这个项目在webLogic运行的时候,垃圾回收可以回收一点点,但是慢慢的就达到上限了,并报full GC
      

  4.   

    我很奇怪为什么map里面存流?map存活多久?  既然存流应该后面会对其进行操作处理吧,那个是否把它close不行吗;流不关闭多少内存都不够耗
      

  5.   

    new BufferedInputStream(new ByteArrayInputStream(byteGz)) 必须要关闭!这是谁写的代码?谁评审的?要是我组内成员写这样的代码,我就使劲xx它一顿...
      

  6.   

    其实如果是ByteArrayInputStream可以不关闭,只要没有引用就会回收但是没有关闭InputStream是一种非常坏的习惯
      

  7.   

    集合里面嵌套大量IO对象,不可取。
    你也说了,如果异常了IO流会不会关闭?这个要搞好异常处理。finally里面去判断一把,做好资源回收。清空集合之前要关闭里面的IO流,再把集合清空
      

  8.   

    无用的BufferedInputStream应当及时关闭
    还有注意静态变量应当适时的、符合业务逻辑地置为null
    原来做过一个东西 就是静态变量没有及时的置为null 导致GC无法回收
    过多的占用内存
      

  9.   


    public static void main(String[] args) {
    for(int i=0;i<100;i++){
    //byte[] byteGz = new byte[1024*1024*1024];//1G
    byte[] byteGz = new byte[1024];//1G
    Map<String,BufferedInputStream> map = new HashMap<String,BufferedInputStream>();
    map.put("a"+i,new BufferedInputStream(new ByteArrayInputStream(byteGz)));
    }
    }
    问题不是出在流上,而是出在byte[]上面。
      

  10.   

    sorry,应该是:public static void main(String[] args) {
    Map<String,BufferedInputStream> map = new HashMap<String,BufferedInputStream>();//一直持有引用不释放,导致内存无法释放
    for(int i=0;i<100;i++){
    byte[] byteGz = new byte[1024*1024*1024];//1G
    //byte[] byteGz = new byte[1024];//1G
    map.put("a"+i,new BufferedInputStream(new ByteArrayInputStream(byteGz)));
    }
    }
      

  11.   

    byte[] byteGz = .....
    Map<String,BufferedInputStream> map = new HashMap<String,new BufferedInputStream>();流都是现用现打开的,然后及时关闭。
    ByteArrayInputStream 虽然不用关,但是字节都存在内存中,不及时释放,服务器迟早会崩溃。要改的话,
    一、把 byte[] byteGz = ..... 存到一个临时文件。
    二、map.put(String, 临时文件路径)
    如果,map 不好改,就在 new BufferedInputStream(new ByteArrayInputStream(byteGz)) 中,自己实现一个流 代替 ByteArrayInputStream,流只保存临时文件的路径。读数据的时候,现生成一个FileInputStream去读数据。
      

  12.   


    请问像我现在这样的逻辑
    map.put("a",new BufferedInputStream(new ByteArrayInputStream(byteGz)));
    ...
    在void createPdf(Map<String,BufferedInputStream> map)方法中,可否只关闭BufferedInputStream?ByteArrayInputStream是否可以在关闭BufferedInputStream后关闭呢?
      

  13.   

    ByteArrayInputStream 中的 close 方法是个空的,也就是说其数据是全部存放在内存中的!其实 ByteArrayInputStream 就是对 byte[] 进行的一个包装!如果你这样做,而且 Map 中还不止一个数据的话,势必要引起内存不足。不了解具体的业务逻辑,以及这样做的理由,无法给你提从解决方案。
      

  14.   

    对,完全正确,你要及时的处理map里面的流并释放掉;参考12楼的代码:public static void main(String[] args){
        Map<String,BufferedInputStream> map = new HashMap<String,BufferedInputStream>();
        for(int i=0;i<10000;i++){
            byte[] byteGz = new byte[1024*1024];//
            map.put("a"+i,new BufferedInputStream(new ByteArrayInputStream(byteGz)));
        }
    }运行这段代码必造成内存溢出。而改成这样后,就没有问题:public static void main(String[] args){
        Map<String,BufferedInputStream> map = new HashMap<String,BufferedInputStream>();
        for(int i=0;i<10000;i++){
            byte[] byteGz = new byte[1024*1024];//
            map.put("a"+i,new BufferedInputStream(new ByteArrayInputStream(byteGz)));
            BufferedInputStream get = map.get("a" + i);
            try {
                get.close();
            } catch (IOException ex) {
                Logger.getLogger(ImageTest.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }这说明BufferedInputStream释放了里面的ByteArrayInputStream也自动释放了,所有拟把BufferedInputStream释放了就行了
      

  15.   

    记得听过这样一个言论,流打开后必须手动关闭,垃圾回收并不知道如何关闭流对象,所以尽管执行了回收,但是流对象在系统中始终还是占有内存的。比如一个打开一个流占用了4K的内存,垃圾回收可能只会回收2K的内存,剩下的2K仍然被流占据着。