Как выделить память из ОС вместо увеличения размера кучи JVM? - PullRequest
0 голосов
/ 30 октября 2009

Мне нужно определить, превышает ли файл, который я прикрепляю к электронному письму, лимит сервера. Мне не разрешено увеличивать размер кучи JVM для этого, так как это повлияет на производительность приложения.

Если я не увеличу размер кучи JVM, я напрямую столкнусь с OutOfMemoryError.

Хотелось бы узнать, как выделить память из ОС вместо увеличения размера кучи JVM?

Большое спасибо!

Ответы [ 7 ]

3 голосов
/ 30 октября 2009

Если вам нужно передать файл на сервер, чтобы узнать, не слишком ли он большой, вам все равно не нужно читать весь файл в память.

Вместо этого прочитайте, может быть, 10-100k в память. Заполните буфер, отправьте его на сервер. Повторяйте до тех пор, пока файл не будет готов или сервер не пожалуется Тогда вам не нужно достаточно памяти для всего файла.

3 голосов
/ 30 октября 2009

Вы действительно пытаетесь прочитать весь файл, чтобы определить его размер, чтобы проверить, не меньше ли оно настроенного значения (ваш вопрос не слишком прост для понимания)? Если да, то почему вы не используете File # length () вместо этого?

1 голос
/ 30 октября 2009

Если вы напишите свой собственный код обработки потока, вы можете создать свой собственный счетчик для отслеживания количества переданных байтов. Я был бы удивлен, если бы уже не было какого-то класса Filter, который сделал бы это для вас. У Sun есть страница об этом . Поиск 'CountReader'.

0 голосов
/ 30 октября 2010

Если вам не разрешено увеличивать размер кучи из-за содержания памяти, выполнение выделения памяти «под таблицей» вызовет те же проблемы. Похоже, вы ищете лазейку в правилах. Например: «Мой доктор говорит, чтобы сократить количество еды во время каждого приема пищи, поэтому я ем больше между приемами пищи, чтобы компенсировать это».

Единственный известный мне способ выделения памяти без использования кучи Java - это писать вызовы JNDI для выделения памяти с C. Но тогда как бы вы использовали эту память? Вы должны написать больше вызовов JNDI для взаимодействия с ним. Я думаю, что вы в конечном итоге заново изобретаете Java.

Если цель здесь - отправить большой файл, просто используйте буферизованные потоки и читайте / записывайте его по одному байту за раз. Буферизованный поток, как следует из названия, позаботится о буферизации для вас, так что вы на самом деле не ударяете по жесткому диску по одному байту за раз. Это будет действительно читать, я думаю, что по умолчанию 8k за один раз, а затем передать эти байты вам, когда вы их просите. Аналогично, на стороне записи это сэкономит несколько килобайт и отправит их всех порциями.

Так что все, что вам нужно сделать, это открыть 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();

Нет необходимости усложнять себе жизнь, заново изобретая буферизацию. время (

0 голосов
/ 02 ноября 2009
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();

Конечно, обработайте ваши исключения.

0 голосов
/ 30 октября 2009

Если все другие решения окажутся непригодными (и я бы посоветовал вам найти лучший способ, чем требование, чтобы весь файл помещался в память!), Вы можете рассмотреть возможность использования прямого ByteBuffer. Он имеет возможность использовать mmap () или другие системные вызовы для отображения файла в вашей памяти без фактического чтения / выделения пространства в куче. Вы можете сделать это, вызвав map () для FileChannel - Документация API . Обратите внимание, что это потенциально дорого и / или не поддерживается на некоторых платформах, поэтому его следует считать неоптимальным по сравнению с любым решением, которое не требует, чтобы весь файл находился в памяти.

0 голосов
/ 30 октября 2009

Вы могли бы выделять память изначально через собственный код и JNI. Однако это звучит болезненно для этого.

Вместо этого вы не можете дать JVM подходящие конфигурации памяти (через -Xmx)? Если документ, который вы отправляете по почте, настолько большой, что вы не можете его легко обработать, то я не уверен, что электронная почта является правильным средством для его передачи, и вы должны вместо этого разместить его и отправить ссылку к нему, или, возможно, FTP это.

...