随笔 - 1, 文章 - 0, 评论 - 10, 引用 - 0
数据加载中……

经典的IO代码为什么有资源泄漏?

最近在开发中,使用到IO操作进行反序列化操作,使用了在各种资料中常见的关于IO操作的经典代码,在自测和测试人员的测试中都没有发现任何问题!
代码如下

public  Object readObject(File file)
    {
        Object o 
=   null ;
        
if  (file.exists())
        {
            ObjectInputStream ois 
=   null ;
            
try
            {
                ois 
=   new  ObjectInputStream( new  FileInputStream(file));
                o 
=  ois.readObject();
            }
            
catch  (Throwable e)
            {
                e.printStackTrace();
            }
            
finally
            {
                
if  (ois  !=   null )
                {
                    
try
                    {
                        ois.close();
                    }
                    
catch  (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }            
        }
        
return  o;
    }

忽然一天测试人员联系我说这部分代码导致系统无法启动,原因仅仅是因为让该部分代码不断的处理一个为序列化文件!
我仔细分析一下代码,没有问题呀,反序列化失败就直接关闭了ois对象,不可能造成资源泄漏,于是用单步跟踪的方式
查看处理非法文件的详细情况:
1、创建FileInputStream 没有问题
2、创建ObjectInputStream失败 没有问题
3、进入catch块,打印堆栈 没有问题
4、进入finnaly块,if (ois != null)为false,这时意识到出问题了
原来创建FileInputStream成功,此时已经申请了资源,但在后续创建ObjectInputStream时失败,但此时又没有保存FileInputStream
的引用,无法释放资源,最终导致了资源泄漏。看来在以后的IO的编程中一定要保存基本流的引用,否则在类似上面的情况
在转换流失败后,无法安全的释放资源!
下面为修改后的代码:

 public Object readObject(File file)
    {
        Object o 
= null;
        
if (file.exists())
        {
            FileInputStream fis 
= null;
            ObjectInputStream ois 
= null;
            
try
            {
                fis 
= new FileInputStream(file);
                ois 
= new ObjectInputStream(fis);
                o 
= ois.readObject();
            }
            
catch (Throwable e)
            {
                e.printStackTrace();
            }
            
finally
            {
                
if (fis != null)
                {
                    
try
                    {
                        fis.close();
                    }
                    
catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }            
        }
        
return o;
    }


posted on 2006-03-24 21:47 mooninwell 阅读(1168) 评论(10)  编辑  收藏 所属分类: Java原创

评论

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

有一点疑问:
在文件存在的情况下,在什么情况下会出现fis创建成功而ois创建失败?
另:finally下还是要加上关闭ois的为好。
2006-03-25 09:14 | 阿伟的技术小巢

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

收到,谢谢分享
2006-03-25 10:30 | flyfoxs

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

频繁调用这个方法OPEN/CLOSE STREAM也不是一个好的做法吧?如果一直使用一个ObjectInputStream/ObjectOutputStream就要小心内存泄漏。
2006-03-25 12:03 | 非鱼

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

只要文件存在并且读的权限就可以成功创建fis,但将fis转换为ois则文件必需满足序列化的文件格式。至于ois的关闭,从理论上关闭了基本流fis就不会存在泄漏,而且在实际测试中,window、solaris、aix系统下都没有问题@阿伟的技术小巢
2006-03-25 20:37 | mooninwell

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

资源和io流是一一对应的,而且良好的编程习惯应该是对独占资源应该尽快的释放,因此处理逻辑应该和从资源中获取信息相分离@非鱼
2006-03-25 20:40 | mooninwell

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

@mooninwell

因OIS/OOS使用HANDLETABLE保存被序列化对象的引用,实践中应注意调用OOS.reset()方法,否则在大量对象序列化时会发生ML。
2006-03-25 21:44 | 非鱼

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

@非鱼
以前工作很少用到IO,特别是序列化部分!今天在你的提醒下,看了一下oos的实现,发现一直使用一个oos/ois的确存在ML的可能性,但我认为这中使用情况在实际应用中很少发生。另:发现OOS的close方法内也包含了reset方法的实现,但ois没有实现reset方法,会抛异常。
2006-03-26 00:45 | mooninwell

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

用InputStream代替File作为参数岂不更好?
2006-03-27 09:49 | hubeicaolei

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

同意楼上的
2006-03-27 10:07 | nkoffee

# re: 经典的IO代码为什么有资源泄漏?  回复  更多评论   

@mooninwell

OIS没有实现reset()方法,是因为它从INPUT流中读取TC_RESET标志来RESET HANDLE TABLE。这样可以保证通过网络SERIALIZATION时不出问题。
2006-03-28 00:01 | 非鱼

只有注册用户登录后才能发表评论。


网站导航: