读写大文件在linux下占用大量内存且不会释放?【急】

csdnjly 2007-12-28 08:28:31
代码如下:
public void copyFile(String oldPath, String newPath) throws Exception
{

int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
if (oldfile.exists())
{ //文件存在时
InputStream inStream = new FileInputStream(oldPath); //读入原文件
FileOutputStream fs = new FileOutputStream(newPath);
byte[] buffer = new byte[1444];
int length;
while ((byteread = inStream.read(buffer)) != -1)
{
bytesum += byteread; //字节数 文件大小
//System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
inStream.close();
fs.close();
}

}

这段代码在本地windows下运行copy大的文件(例如100M以上)检测内存的使用发现只是使用了buffer大小的内容,
但是放到linux系统websphere的jsp/servlet运行用top命令检测发现占用了大量的内存,并且程序执行完毕之后内存占用率仍然高居不下。

其实我原本的问题是在websphere上的一个servlet用ftp从另外一台linux服务器读取文件(InputStream)然后把InputStream的字节流out put到客户端给客户下载,但是发现这里的读取/写入操作占用了大量的内存,就跟上面的复制文件情况相似。问题出在In/Out Stream的操作上,但是windows下运行却没有这样的问题。

期盼各位鼎立相助,在下感激不尽!
...全文
2065 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
csdnjly 2008-01-06
  • 打赏
  • 举报
回复
这难道是linux系统的bug?
csdnjly 2008-01-01
  • 打赏
  • 举报
回复
事实证明不是这样啊,多用户下会把websphere扯死
老紫竹 2007-12-29
  • 打赏
  • 举报
回复
我印象中也是这样的。 linux 会看上去可用内存非常少,可以还能运行很占内存的程序,比如启动oracle, 所以,直到内存不足再释放应该是对的!
csdnjly 2007-12-28
  • 打赏
  • 举报
回复
刚搜索到这个答案,不知是不是正解:
Linux内存计数详解
又中计了……
近几天用oracle,发现oracle狂用内存,经常内存小到10M的规模。汗一个,赶快让经理买了新的1G内存来装,上去后发现根本认不出来。加班一多小时才发现386内核根本不认高端内存(HIGHMEM),所以内存极限一直是896M。以前是1G内存,所以看不出来,现在换了1.5G,看出来了。
赶快上了一个2.6.12-1-686的内核,然后重启,认出来了。不过free还是只有32M左右,我们大惊小怪的打电话到oracle那里去咨询,得到的答复是要安装完整的补丁,并且要用oracle认证过的服务器。oracle认证了啥服务器?RedHatEnterpriseAS3/4,那个东西要收费的,而且绝对不便宜。最后无奈,做了一次不启动oracle的测试。出乎我们意料的,mysql吃了多数的内存。具体造成这种状况的原因是啥呢?
偶查阅了linux内存管理资料,发现linux的内存管理计数上讲的东西和windows讲的有很大差异。下面具体列举下几种计数、查看方式和含义。
total mem,可以用top free查看出来。
free mem,可以用top free vmstat查看出来。
used mem,可以用top free查看出来.
buffer mem,可以用top free vmstat查看出来。
shared mem,可以用free查看出来。
swap mem,可以用top查看出来。
swap used,可以用top vmstat查看出来。
cached mem,可以用top free vmstat查看出来。
active mem,可以用free vmstat -a查看出来,即cached used。
inactive mem,可以用free vmstat -a查看出来,即cached free。
其中total mem是除去系统外的可用内存,系统大约占1M多。然后分配给free mem和used mem。used mem又包括了内核表使用(例如GDT),程序使用,buffer,cached。所以
cached mem=active mem+inactive mem
total mem=free mem+used mem
used mem=内核表使用+程序使用物理内存+buffer mem+cached mem
略去内核表使用,这个式子可以变形成这样:
程序使用总内存=swap used+程序使用物理内存
=swap used+used mem-buffer mem-cached mem
=total mem-free mem+swap used-buffer mem-cached mem
根据所有系统内存管理的恒等式:
程序使用总内存+一次可申请内存=total mem+swap used
我们可以计算出:
一次可申请内存=free mem+buffer mem+cached mem(事实上要略小于这个值)
程序使用的部分swap出去部分,占用total部分,剩下的就是一次可以申请的最大值。多次申请造成这个值太小就继续向swap里面交换。

首先解释buffer和cached区别。通俗的讲,buffer中放的是对象数据结构,而cached中放的是无结构的块数据。cached可以缓冲任何标准的块设备,而不用管是什么东西。其中涉及写通和写回的概念,大家自己看去吧。
然后是程序使用物理内存的概念。程序的总内存等于交换出去的部分加上程序使用物理内存。而程序使用的总内存和各个程序的内存占用是什么关系呢?这个又要涉及共用页面的问题。
windows中也有类似概念,如果两个页面内容相同,那么在内存中保留一份就可以了。这个是动态链接库/动态共享库的理论基础。所以所有进程的shared mem只有一份copy。进程使用的Data+Stack是数据空间,code是代码空间,两者和减去shared mem是私有空间,也就是俗称的进程内存占用。将所有内存占用求和加上shared mem的和,就得到了程序的总内存。
Linux的cached和windows的一个很大差异在于,windows的磁盘缓存是读写缓存队列。写入操作和预读取操作在队列中排序。完了就释放了,主要用于平缓读写瓶颈。读取预测机制才是增加命中的重头。linux的cached读写完了一直不释放,直到内存不足再释放。释放的速度来说应该是没有问题的,毕竟数据已经写入了,只差一个数据结构标志位修改而已。这种机制主要对应高命中率,如果重复使用相同文件(应该说是相同块设备的相同offset)。那么缓存机制永远只要读一次,写入次数也远远小于应当的写入次数。

根据上面一次可申请内存的计算公式,可以知道这次偶死在哪里了吧。

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧