トップ回答者
.Net RemotingにおけるOutOfMemoryException

質問
-
がっちんと申します。
お世話になります。
現在、.Net Remotingを利用したクライアント/サーバ アプリケーションを開発しています。
このアプリケーションではクライアントからサーバに対してファイルのアップロードを行っており、
ファイルをByte[]に読み込んだ後、リモーティングのクラスメソッドにてByte[]を送信しています。
しかし、小さなファイルは問題なく動作するのですが、やや大容量のファイル(80MB)で実行すると
OutOfMemoryExceptionが出てしまいます。実行環境のPCはメモリが2GBあり、普段は滅多に
OutOfMemoryExceptionはでることがないのですが、.Net Remotingではすぐにこれが出現しま
す。
.Net Remotingでは利用可能なメモリリソースが制限されているのでしょうか?
あるいは、僕のプログラムコードに不具合があるのでしょうか?
また、根本的に、この様なファイルアップロード処理で.Net Remotingを使用することは間違って
いて、やはりTCPの通信APIを使うべきなのでしょうか?
もし何かアドバイスがあればよろしくお願いします。
主な部分のプログラムコードは以下の通りです。
(OS:WinXP, VisualStudio2005 .NET Framework2.0を利用)
■クライアント側
HttpServerChannel clientChannel = new HttpServerChannel();
ChannelServices.RegisterChannel(clientChannel, false);NewTaskObject msg = (NewTaskObject)Activator.GetObject(typeof(NewTaskObject),
http://192.168.0.100:9999/newTask);
//タイムアウトの設定
System.Collections.IDictionary props = ChannelServices.GetChannelSinkProperties(msg);
props["Timeout"] = 100000;//アップロードするファイル
string fileName = "D:\testFile";
byte[] fileByte = File.ReadAllBytes(fileName);
//リモーティングの実行
msg.SendMsg(fileName,fileByte);
■サーバ側
public void StartServer(){
HttpServerChannel servChannel = new HttpServerChannel("Task", 9999);
ChannelServices.RegisterChannel(servChannel, false);
// イベントを登録
NewTaskObject msg = new NewTaskObject();
msg.eventCall += new NewTaskObject.CallHandler(msg_eventCall);
RemotingServices.Marshal(msg, "newTask", typeof(NewTaskObject));}
public void msg_eventCall(string fileName,byte[] fileByte){
FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
fs.Write(fileByte, 0, fileByte.Length);
fs.Close();・・・・・・・・
・・・・・・・・
}
回答
-
ためしにバイナリフォーマッタでやってみたらどうなります?
SoapFormatterは結構メモリ食いなので、想像以上の連続メモリを消費している可能性もある気がします。
BinaryFormatterだと、byte配列なんかはかなり効率よく処理できた気がします。
ただ、Remotingでは送り側も受け側もオンメモリでシリアライズ前、作業領域、シリアライズ後のメモリを使用するので、あまり大きなデータの直接的な受け渡しには向きません。
例えばバイナリフォーマッタを使用しても送り側と受け側で合わせて、少なくともシリアライズ前、シリアライズ後、デシリアライズ前、デシリアライズ後分のメモリが同時使用される可能性があります(同一マシンで試した場合)。
まあ、ASP.NETでのファイルのアップロードも確かオンメモリで一気に処理してしまいますし、ダウンロードも単純にやれば同じようなことにはなりますが。
簡単にやるなら、データをレンジ分けして分割で送信するなどすれば、ある程度対応はできると思います。
-
なちゃ さんからの引用 ためしにバイナリフォーマッタでやってみたらどうなります?
SoapFormatterは結構メモリ食いなので、想像以上の連続メモリを消費している可能性もある気がします。
BinaryFormatterだと、byte配列なんかはかなり効率よく処理できた気がします。
HttpServerChannelのSoapFormatterを使っていたのですが、アドバイス通りTcpServerChannelで
BinaryFormatterを使用することで、メモリ消費が格段に減りOutOfMemoryが出なくなり問題を解決
することができました。
とても勉強になりました。
ありがとうございました。
すべての返信
-
がっちん さんからの引用 しかし、小さなファイルは問題なく動作するのですが、やや大容量のファイル(80MB)で実行すると OutOfMemoryExceptionが出てしまいます。実行環境のPCはメモリが2GBあり、普段は滅多に
OutOfMemoryExceptionはでることがないのですが、.Net Remotingではすぐにこれが出現しま
す。
私は Remoting は普段使用していないのでどちらか知らないのですが,.NET Remoting の場合,サーバサイドで例外が発生した場合も,ローカルで例外が起きたように見えるのでしょうか? それとも サーバサイドで発生した例外は,クライアントサイドでは何かラップされて見えるのでしょうか?
「実行環境のPCはメモリが2GBあり」とありますが,サーバ/クライアントは同一の PC なのか否か,OutOfMemoryException の原因はサーバサイドかクライアントサイドか,などは注意してみた方がいいのではないでしょうか?
-
ためしにバイナリフォーマッタでやってみたらどうなります?
SoapFormatterは結構メモリ食いなので、想像以上の連続メモリを消費している可能性もある気がします。
BinaryFormatterだと、byte配列なんかはかなり効率よく処理できた気がします。
ただ、Remotingでは送り側も受け側もオンメモリでシリアライズ前、作業領域、シリアライズ後のメモリを使用するので、あまり大きなデータの直接的な受け渡しには向きません。
例えばバイナリフォーマッタを使用しても送り側と受け側で合わせて、少なくともシリアライズ前、シリアライズ後、デシリアライズ前、デシリアライズ後分のメモリが同時使用される可能性があります(同一マシンで試した場合)。
まあ、ASP.NETでのファイルのアップロードも確かオンメモリで一気に処理してしまいますし、ダウンロードも単純にやれば同じようなことにはなりますが。
簡単にやるなら、データをレンジ分けして分割で送信するなどすれば、ある程度対応はできると思います。
-
アドバイスをいただきありがとうございます。
>>NyaRuRuさん
Remotingでは、サーバ側でエラーが発生するとサーバ側でまずなんらかのException
がでます。その影響でクライアント/サーバ間のHTTPやTCPで接続されたコネクションが遮断
されるとクライアント側でRemotingExceptionが発生します。
今回はサーバ側でもデバックモードでアプリケーションを起動しエラーの内容を確かめたところ
OutOfMemoryExceptionが発生していました。PCのメモリはサーバPCもクライアントPCも2GB
となっています。
また、同一PCでサーバ/クライアントのRemotingをやってみたところやはりうまくいかずエラーの
原因がOutOfMemoryExceptionとなっていました。
>>なちゃさん
なるほど、バイナリフォーマッタで試しにやってみることにします。
またレンジ分けで分割送信も試してみることにします。
またのちほどご報告させていただきたいと思います。
-
なちゃ さんからの引用 ためしにバイナリフォーマッタでやってみたらどうなります?
SoapFormatterは結構メモリ食いなので、想像以上の連続メモリを消費している可能性もある気がします。
BinaryFormatterだと、byte配列なんかはかなり効率よく処理できた気がします。
HttpServerChannelのSoapFormatterを使っていたのですが、アドバイス通りTcpServerChannelで
BinaryFormatterを使用することで、メモリ消費が格段に減りOutOfMemoryが出なくなり問題を解決
することができました。
とても勉強になりました。
ありがとうございました。