- PR -

Servlet ファイルダウンロードを実現する際のメモリ占有

1
投稿者投稿内容
Topica
会議室デビュー日: 2005/01/26
投稿数: 8
投稿日時: 2005-01-26 15:54
Servlet でファイルのダウンロードを実現する手法として,
doPost で Response の OutputStream にファイルを読み込んだバイトデータを
そのまま書き込む方法があります。

この方法で大きなファイルをOutputStream書き込んだ場合は,
メモリをその分占有してしまうのでしょうか。
また,クライアント側には,
ファイルの全データをStreamにすべてのデータを書込み終え,
doPostの実行が終了した段階でResponse が返るのでしょうか。

書き方が荒っぽくて恐縮ですが,
おそらくStreamに流したデータがどこにストアされ,
どのようなタイミングで開放されるのかが
よく理解できていないのだと思います。

どなたかご教示いただけましたら助かります。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2005-01-26 16:27
レスポンスに書き込んだデータはある程度バッファに溜めてから送信されます。
出力するファイルのサイズだけヒープを占有してしまう、ということはありませんのでご安心ください。
詳しくは仕様書や API の ServletResponse#getBufferSize()/setBufferSize()/commit() あたりをご覧ください。
Topica
会議室デビュー日: 2005/01/26
投稿数: 8
投稿日時: 2005-01-27 11:55
インギさん,ご回答ありがとうございました。
APIドキュメントを早速読んでみました。が・・・
すみません,まだ腑に落ちていません。

作成したサンプルでは,
ServletResponse の OutputStream に対して,
ファイル内容を一気に書き込みます。
そして,書き込み終わると,はじめてdoPostを抜けます。

クライアントは,ブラウザではなくDelphiで作成したアプリです。
HTTP通信を行うコンポーネントを使用してServletに対してPostしてます。

// Delphiコードですみません,HTTPは通信を行うオブジェクト,
// response はストリームです
Http.Post(url, param, response);

この呼び出しが返り次第,responseからデータを受け取っていくのですが,
Servlet側でdoPostを抜けない限り,この呼び出しも戻りません。
つまり,ファイルのデータをすべてストリームに入れた時点で,
はじめて受信が開始されることになります。
この場合,やはりファイルデータがすべてメモリに展開されてしまうことに
なるように思うのです。

別スレッドを使ってdoPostをすぐ抜けるようにしてしまえばいいのでしょうか。
ただ,その場合も,ファイルデータをストリームに書き込んでいく
(自分で書いた)処理と,
受信・送信処理が同期を取っているのではないわけですから,
たとえば受信が遅れた場合,やはりメモリにデータが積みあがっていくような
気がします。
このあたりをどこか根本的に勘違いしているのでしょうか・・・
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2005-01-27 13:54
Http.Post()とやらの関数の仕様をきちんと調査した方が良いかと思い
ます。

Httpクライアント側で使用するAPIライブラリが、Httpリクエスト送信
メソッドを、「リクエスト送信〜レスポンス受信完了まで待機(途中で
エラーが発生したら例外送出など)」とするよう実装するのは、通常の
ことかと思いますよ。


HttpServletResponseが所有するOutputStreamは、文字通りストリーム
ですので、ストリームのバッファサイズを超えるメモリを消費することは
無いですよ。下のレイヤはソケットですので、送信先の受け取り処理が
間に合って無い状態で、送信元でバッファがあふれるほどwriteしようと
すれば、writeの呼び出しで、writeを呼び出しているスレッドがブロック
するはずです。


[ メッセージ編集済み 編集者: シュン 編集日時 2005-01-27 13:57 ]
Topica
会議室デビュー日: 2005/01/26
投稿数: 8
投稿日時: 2005-01-27 14:53
シュンさん,ご回答ありがとうございます。

>送信元でバッファがあふれるほどwriteしようとすれば、
>writeの呼び出しで、writeを呼び出しているスレッドがブロックするはずです。

これが知りたかったことです!すっきりしました。

Webブラウザの場合もdoPostを抜けるまで応答がないものと勘違いしておりました
(実際はそうでないことを確認しました)。
ただ,ここでWebブラウザ,WebサーバとServletコンテナの間で
何が起こっているのかは残念ながらよく理解していません。

クライアント側HTTPモジュールのPostメソッドが
Responseの応答を待つ仕様なのは確認しました。
となると,スレッドを使用してdoPostはすぐに抜けるように実装する方向で
サンプルを作ってみようと思っています。
結果が出ましたらポストします。ありがとうございました。
Topica
会議室デビュー日: 2005/01/26
投稿数: 8
投稿日時: 2005-01-27 20:57
>スレッドを使用してdoPostはすぐに抜けるように実装する方向で

これも結局のところ私の勘違いでした。

// Delphiコードですみません。
// HTTPは通信を行うオブジェクトです。
// response にファイル出力ストリームを渡したところ,
// 一気にファイルに落とす処理を実装できました。
// 余談ですが,Servlet側で DeflaterOutputStream を使用しているため,
// クライアントで解凍処理を行う必要があるのですが,
// "解凍を行うOutputStream" が存在しないため,自作する必要があり,
// かなり悪戦苦闘しました(泣)
Http.Post(url, param, response);

なんとかサンプルを動作させることができました。
どうもありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)