Monotouch和WCF,内存使用
我在网站和 Monotouch 应用程序中托管了 WCF 服务,可以通过服务显示和更新 PDF 文档。 PDF 文件大小可以从 1 字节到 20 Mb。 当我的文档很少(少于 100 个,文档总大小为 30Mb)时,更新过程成功完成。但是,当我有很多文档(超过300个,常见文档大小为100Mb)时,我的程序在iPad 1上终止,但在iPad 2上仍然可以运行。
我认为问题出在内存使用上。当我的应用程序使用大量内存时,iOS 会杀死它。但我不知道问题出在哪里,也许 Monotouch GC 没有从 fileData 字节数组中清理内存?
iPad上更新文档的方法:
protected bool BeginUpdateProcess()
{
try {
var binding = new BasicHttpBinding();
binding.MaxBufferSize = 52428800;
binding.MaxBufferPoolSize = binding.MaxReceivedMessageSize = 52428800L;
binding.ReaderQuotas.MaxStringContentLength = binding.ReaderQuotas.MaxArrayLength = 52428800;
var endpoint = new EndpointAddress(string.Format("http://{0}/Services/UpdateDataService.svc", UpdateInfo.Instance.ServerIP));
using (var dataService = new UpdateDataServiceClient(binding, endpoint)) {
// Get document list for update
int[] docIds;
try {
docIds = dataService.GetModifiedDocumentIds(mLastUpdated);
} catch (Exception ex) {
LogWriter.Instance.WriteToLog("UpdateFromServiceEror: Can't load modified document ids list", ex);
return false;
}
// Get each document content and save it to iPad
for (int i = 0; i < docIds.Length; i++) {
if (Canceled) {
return true;
}
try {
byte[] fileData = dataService.GetDocumentTransData(docIds[i]);
SaveDocument(fileData);
} catch (Exception ex) {
LogWriter.Instance.WriteToLog(string.Format("Can't load or save file, id={0}", docIds[i]), ex);
return false;
}
}
dataService.Close();
}
} catch (Exception ex) {
LogWriter.Instance.WriteToLog("Error when update from service", ex);
}
}
网站WCF设置:
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="Transport"
closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="52428800" maxBufferPoolSize="524288" maxReceivedMessageSize="52428800"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="64"
maxStringContentLength="52428800"
maxArrayLength="52428800"
maxBytesPerRead="16384"
maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="iDict.Site.Services.UpdateDataService" behaviorConfiguration="Default">
<host>
<baseAddresses>
<add baseAddress="http://localhost:57709/Services/UpdateDataService.svc"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="Transport" contract="iDict.Site.Services.IUpdateDataService" />
</service>
</services>
I have WCF service hosted in web-site and Monotouch application which can display and update PDF documents from service. PDF files size can be from 1 byte to 20 Mb.
When I have few documents (less than 100, and total size of documents is 30Mb), the update process completes succesfully. But, when I have many documents (more than 300, and common size of documents is 100Mb), my program is terminating on iPad 1, but on iPad 2 is still working.
I think the problem in memory usage. iOS kills my app, when its uses many memory. But I don't know where the problem, maybe Monotouch GC don't clean memory from fileData byte arrays?
Method which update documents on iPad:
protected bool BeginUpdateProcess()
{
try {
var binding = new BasicHttpBinding();
binding.MaxBufferSize = 52428800;
binding.MaxBufferPoolSize = binding.MaxReceivedMessageSize = 52428800L;
binding.ReaderQuotas.MaxStringContentLength = binding.ReaderQuotas.MaxArrayLength = 52428800;
var endpoint = new EndpointAddress(string.Format("http://{0}/Services/UpdateDataService.svc", UpdateInfo.Instance.ServerIP));
using (var dataService = new UpdateDataServiceClient(binding, endpoint)) {
// Get document list for update
int[] docIds;
try {
docIds = dataService.GetModifiedDocumentIds(mLastUpdated);
} catch (Exception ex) {
LogWriter.Instance.WriteToLog("UpdateFromServiceEror: Can't load modified document ids list", ex);
return false;
}
// Get each document content and save it to iPad
for (int i = 0; i < docIds.Length; i++) {
if (Canceled) {
return true;
}
try {
byte[] fileData = dataService.GetDocumentTransData(docIds[i]);
SaveDocument(fileData);
} catch (Exception ex) {
LogWriter.Instance.WriteToLog(string.Format("Can't load or save file, id={0}", docIds[i]), ex);
return false;
}
}
dataService.Close();
}
} catch (Exception ex) {
LogWriter.Instance.WriteToLog("Error when update from service", ex);
}
}
Web-site WCF settings:
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="Transport"
closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="52428800" maxBufferPoolSize="524288" maxReceivedMessageSize="52428800"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="64"
maxStringContentLength="52428800"
maxArrayLength="52428800"
maxBytesPerRead="16384"
maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="iDict.Site.Services.UpdateDataService" behaviorConfiguration="Default">
<host>
<baseAddresses>
<add baseAddress="http://localhost:57709/Services/UpdateDataService.svc"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="Transport" contract="iDict.Site.Services.IUpdateDataService" />
</service>
</services>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
以下几点可能对您有帮助:
52428800 是设备的大缓冲区;
PDF 文档是否以 XML 格式传输?如果是这样,在某个时刻,您的 PDF 文档将同时存在于
string
中(效率不高,内存不足)和byte[] fileData
中。这可能会超过第一代 iPad 的可用 RAM。避免这种情况的一种可能方法是使用可返回文件 URL 的 Web 服务。然后,每个 URL 都可以轻松地从 Web 服务器流式传输
到本地文件,而无需使用太多内存;iPad2 具有更多的 RAM,上述内容可能适用于它们,但对于较大的文档,这最终会失败。同时,使用
Stream
会限制您设备的存储空间;根据您使用的 MonoTouch 版本,您可能会遇到 错误#386。如果可以的话,我建议您尝试最新的 MonoTouch 版本(目前为测试版),它可以解决这些问题。
Here's a few things that might help you:
52428800 is a big buffer for devices;
Are the PDF documents transfered in XML ? If so you'll, at some point, have both your PDF document in a
string
(not very efficient, memory wise) and abyte[] fileData
. That might go over the available RAM of the first generation iPad. A possible way to avoid this situation is having the web service that returns URLs to the files. Each URL can then be easilyStream
'ed from a web server to a local file without using much memory;the iPad2 has more RAM the above might works on them but this would eventually fail for larger documents. Meanwhile using
Stream
would limit you to the storage space of the devices;Depending on the version of MonoTouch you're using you might be hitting bug #386. If you can I suggest you to try the latest MonoTouch release (beta at the moment) which solves those issues.