我需要检测我附加到电子邮件的文件是否超出服务器限制。我不允许增加JVM堆大小来执行此操作,因为它会影响应用程序性能。
如果我不增加JVM堆大小,我将直接遇到OutOfMemoryError。
我想知道如何从OS分配内存而不是增加JVM的堆大小?
非常感谢!
答案 0 :(得分:3)
您是否真的尝试读取整个文件以确定其大小,以检查它是否小于某个配置值(您的问题不太容易理解)?如果是这样,为什么不使用File#length()?
答案 1 :(得分:3)
如果您需要将文件流式传输到服务器以查明它是否太大,您仍然不需要将整个文件读入内存。
相反,可能会将10-100k读入内存。填充缓冲区,将其发送到服务器。重复,直到文件完成或服务器抱怨。然后你不需要足够的内存来存储整个文件。
答案 2 :(得分:1)
如果编写自己的流处理代码,则可以创建自己的计数器来跟踪传输的字节数。如果没有某种Filter类为你做这件事,我会感到惊讶。 Sun has a page about this。搜索'CountReader'。
答案 3 :(得分:0)
你可以通过本机代码和JNI本地分配内存。然而,这听起来很痛苦。
相反,您不能为JVM提供合适的内存配置(通过-Xmx
)?如果你邮寄的文件是那么大而你无法轻易处理它,那么我不确定电子邮件是否是传送它的正确媒介,你应该主持它并发送一个链接到它,或者FTP它。
答案 4 :(得分:0)
如果所有其他解决方案都变得无法使用(我建议您找到一种更好的方法,而不是要求整个文件适合内存!)您可以考虑使用直接的ByteBuffer。它可以选择使用mmap()或其他系统调用将文件映射到内存中,而无需实际读取/分配堆中的空间。您可以通过在FileChannel上调用map() - API documentation来完成此操作。请注意,这在某些平台上可能很昂贵和/或不受支持,因此与任何不需要整个文件存储在内存中的解决方案相比,它应被视为次优。
答案 5 :(得分:0)
Socket s = /* go get your socket to the server */
InputStream is = new FileInputStream("foo.txt");
OutputStream os = s.getOutputStream();
byte[] buf = new byte[4096];
for(int len=-1;(len=is.read(buf))!=-1;) os.write(buf,0,len);
os.close();
is.close();
当然可以处理您的例外情况。
答案 6 :(得分:0)
如果由于内存不足而不允许增加堆大小,那么执行“在表下”内存分配会导致相同的问题。这听起来像是在寻找规则中的漏洞。就像,“我的医生说要减少我每顿饭吃多少,所以我在两餐之间吃得更多,以弥补它。”
我知道在不使用Java堆的情况下分配内存的唯一方法是使用C将内存的JNDI调用写入malloc。但是那么你将如何使用这个内存?你必须编写更多的JNDI调用来与它进行交互。我认为你最终会重新发明Java。
如果这里的目标是发送一个大文件,只需使用缓冲流并一次读/写一个字节。顾名思义,缓冲流将为您进行缓冲,因此您实际上并不是一次一个字节地击中硬盘驱动器。它会真正读取,我认为默认值是8k,然后在你要求时将这些字节传递给你。同样,在写入方面,它将节省几kb,并以块的形式发送它们。
所以你应该做的就是打开一个BufferedInputStream和一个BufferedOutputStream。然后编写一个循环,从输入流中读取一个字节并将其写入输出流,直到您到达文件结尾。
类似的东西:
OutputStream os=... however you're getting your socket ...
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(fileObject));
BufferedOutputStream bos=new BufferedOutputStream(os);
int b;
while ((b=bis.read())!=-1)
bos.write(b);
bis.close();
bos.close();
不需要通过重新发明缓冲来让生活复杂化。 而(