PDFViewCtrl 未处理
PDFViewCtrl not disposed
我们正在开发一个使用 PDFTron 的应用程序。我们注意到,当打开显示分配内存的 Activity 时,分配的内存增加了很多。离开 activity 后,只有一部分内存再次被释放。一些 PDFtron 零件被留下了。
问题是 activity 似乎没有完成,即使我们已经将 activity 设置为 NoHistory 和 singleTask。我看过一些关于内存管理的课程,但无法弄清楚是什么原因导致 activity 保持打开状态。
在我们调用 activity 上的 Finish();
之前,我们处理了 PdfViewCtrl。然后在OnDestroy中:
protected override void OnDestroy()
{
base.OnDestroy();
if (_mPdfViewCtrl == null) return;
_mPdfViewCtrl.Destroy();
_mPdfViewCtrl = null;
}
如果长时间使用该应用程序,会导致内存不足错误。
--- End of managed Java.Lang.Error stack trace ---
java.lang.OutOfMemoryError
dalvik.system.NativeStart.run(Native Method):0
或
--- End of managed Java.Lang.Error stack trace ---
java.lang.OutOfMemoryError
android.graphics.Bitmap.nativeCreate(Native Method):0
android.graphics.Bitmap.createBitmap(Bitmap.java:726):0
android.graphics.Bitmap.createBitmap(Bitmap.java:703):0
android.graphics.Bitmap.createBitmap(Bitmap.java:670):0
pdftron.PDF.Utils.SignaturePickerDialog$SignatureView.onSizeChanged(SignaturePickerDialog.java:244):0
android.view.View.sizeChange(View.java:15326):0
android.view.View.setFrame(View.java:15290):0
android.view.View.layout(View.java:15201):0
android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677):0
android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531):0
android.widget.LinearLayout.onLayout(LinearLayout.java:1440):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677):0
android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531):0
android.widget.LinearLayout.onLayout(LinearLayout.java:1440):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2263):0
android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2009):0
android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1251):0
android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6379):0
android.view.Choreographer$CallbackRecord.run(Choreographer.java:791):0
android.view.Choreographer.doCallbacks(Choreographer.java:591):0
android.view.Choreographer.doFrame(Choreographer.java:561):0
android.view.Choreographer$FrameHandler.handleMessage(Choreographer.java:693):0
android.os.Handler.dispatchMessage(Handler.java:99):0
android.os.Looper.loop(Looper.java:137):0
android.app.ActivityThread.main(ActivityThread.java:5493):0
java.lang.reflect.Method.invokeNative(Native Method):0
java.lang.reflect.Method.invoke(Method.java:525):0
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209):0
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025):0
dalvik.system.NativeStart.main(Native Method):0
在模拟会话的打印屏幕下方(Android 工作室监控):
已编辑 OnDestroy:
var old_tool = _mPdfViewCtrl.ToolManager;
var old_doc = _mPdfViewCtrl.Doc;
_mPdfViewCtrl?.CloseDoc();
_mPdfViewCtrl?.CloseTool();
_mPdfViewCtrl?.Destroy();
_mPdfViewCtrl = null;
_mPdfViewCtrl?.Dispose();
if (old_doc != null)
{
old_doc.Dispose();
}
if (old_tool != null)
{
old_tool.Dispose();
}
如果您的 Activity 也有对 PDFDoc 对象的引用,那么您也应该处理它。这是推荐的方式。
protected override void OnDestroy()
{
base.OnDestroy();
if (_mPdfViewCtrl == null) return;
_mPdfViewCtrl.Destroy();
_mPdfViewCtrl = null;
if(_mPdfDoc != null)
{
_mPdfDoc.Dispose();
}
}
或更普遍
protected override void OnDestroy()
{
base.OnDestroy();
if (_mPdfViewCtrl == null) return;
PDFDoc old_doc = _mPdfViewCtrl.Doc;
_mPdfViewCtrl.Destroy();
_mPdfViewCtrl = null;
if(old_doc != null)
{
old_doc.Dispose();
}
}
从这个link:
"问:我有一个用户选择文件的页面,另一个用户查看所选 PDF 的页面。当用户从 PDF 查看页面导航回文件页面时,我想清理使用的资源by PDFNet。清理工具、PDFViewCtrl 和 PDFDoc 的正确顺序是什么。
答:需要先调用PDFViewCtrl.CloseDoc(),然后才能调用PDFDoc.Dispose()。
对于使用 PDFViewCtrl 的任何页面,都可以放入 OnNavigatedFrom。
此外,PDFViewCtrl 不能手动处理,相反,我们添加了一个 PDFViewCtrl.FreeResources 来删除所有底层结构,这意味着在垃圾收集器启动之前使用的内存更少。
我想补充一下:
PDFDoc doc = this.PDFViewCtrl.GetDoc();
this.PDFViewCtrl.CloseDoc();
if (doc != null)
{
await CloseDocAsync(doc);
}
this.PDFViewCtrl.FreeResources();
CloseDocAsync 只是在后台线程中调用 doc.Dispose(如果它是一个大而复杂的文档)。这可能没有必要,因为我所知道的所有文件都会很快处理掉。但它不疼。 UI 线程即使延迟 200 毫秒也可能会造成破坏。
要记住的一件事是,为了让垃圾收集器回收 PDFViewCtrl,所有注册到它的事件都需要注销。这就是为什么当您离开页面时也应该调用 ToolManager.Dispose() 的原因。
在这种情况下,只需在我上面添加的任何代码之前调用 ToolManager.Dispose。"
如果上述 none 有帮助,您可以尝试在提供优先技术支持的 PDFTron forum. The company also has a tech support option 中重新发布您的问题。根据您使用的版本,技术支持可能是免费的。
编辑
我为文档提供的 links 是针对 Windows 版本的,而不是 Android。这是 PDFViewCtrl and PDFDoc.
的 Android 版本 link
因此,我上面提供的 link 中的代码对您不起作用。您可能会尝试做的只是关闭文档。有一个 CloseDoc 方法可以从 PDFViewCtrl class 中调用。如果这不起作用,请尝试从 PDFDoc 方法调用 Close 方法。 PDFViewCtrl class 有一个名为 getDoc 的方法,它 returns 当前文档,它是一个 PDFDoc。文档说 PDFDoc.close 方法是一个析构函数。所以,试试这两个想法。
我注意到的另一件事是 PDFViewCtrl class 中有锁定和解锁方法。如果上述 2 个想法不起作用,您可以尝试在调用 close 方法之前调用 docUnlock 方法。这个想法是,如果文档被锁定,关闭调用可能会挂起或超时。
现在,如果 none 有效,那么您正在做的其他事情是否正在消耗内存?您或您团队中的其他人是否有可能忘记为您可能正在做的其他事情清理内存?是否有人使用 C++,或者可能使用 API,它在底层使用 C++ 并且忽略了删除内存,或者调用适当的关闭方法来正确清理?
使用探查器可能有助于回答这些问题。有第 3 方分析器可用,或者您可以尝试 Microsoft .NET Memory Analyzer。我不知道它是否会起作用 Android。它还需要 .NET Framework 4.5 或更高版本。
还有一个 Xamarin profiler,这可能是一个更好的开始选择。
我们正在开发一个使用 PDFTron 的应用程序。我们注意到,当打开显示分配内存的 Activity 时,分配的内存增加了很多。离开 activity 后,只有一部分内存再次被释放。一些 PDFtron 零件被留下了。
问题是 activity 似乎没有完成,即使我们已经将 activity 设置为 NoHistory 和 singleTask。我看过一些关于内存管理的课程,但无法弄清楚是什么原因导致 activity 保持打开状态。
在我们调用 activity 上的 Finish();
之前,我们处理了 PdfViewCtrl。然后在OnDestroy中:
protected override void OnDestroy()
{
base.OnDestroy();
if (_mPdfViewCtrl == null) return;
_mPdfViewCtrl.Destroy();
_mPdfViewCtrl = null;
}
如果长时间使用该应用程序,会导致内存不足错误。
--- End of managed Java.Lang.Error stack trace ---
java.lang.OutOfMemoryError
dalvik.system.NativeStart.run(Native Method):0
或
--- End of managed Java.Lang.Error stack trace ---
java.lang.OutOfMemoryError
android.graphics.Bitmap.nativeCreate(Native Method):0
android.graphics.Bitmap.createBitmap(Bitmap.java:726):0
android.graphics.Bitmap.createBitmap(Bitmap.java:703):0
android.graphics.Bitmap.createBitmap(Bitmap.java:670):0
pdftron.PDF.Utils.SignaturePickerDialog$SignatureView.onSizeChanged(SignaturePickerDialog.java:244):0
android.view.View.sizeChange(View.java:15326):0
android.view.View.setFrame(View.java:15290):0
android.view.View.layout(View.java:15201):0
android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677):0
android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531):0
android.widget.LinearLayout.onLayout(LinearLayout.java:1440):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677):0
android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531):0
android.widget.LinearLayout.onLayout(LinearLayout.java:1440):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.widget.FrameLayout.onLayout(FrameLayout.java:448):0
android.view.View.layout(View.java:15204):0
android.view.ViewGroup.layout(ViewGroup.java:4793):0
android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2263):0
android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2009):0
android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1251):0
android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6379):0
android.view.Choreographer$CallbackRecord.run(Choreographer.java:791):0
android.view.Choreographer.doCallbacks(Choreographer.java:591):0
android.view.Choreographer.doFrame(Choreographer.java:561):0
android.view.Choreographer$FrameHandler.handleMessage(Choreographer.java:693):0
android.os.Handler.dispatchMessage(Handler.java:99):0
android.os.Looper.loop(Looper.java:137):0
android.app.ActivityThread.main(ActivityThread.java:5493):0
java.lang.reflect.Method.invokeNative(Native Method):0
java.lang.reflect.Method.invoke(Method.java:525):0
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209):0
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025):0
dalvik.system.NativeStart.main(Native Method):0
在模拟会话的打印屏幕下方(Android 工作室监控):
已编辑 OnDestroy:
var old_tool = _mPdfViewCtrl.ToolManager;
var old_doc = _mPdfViewCtrl.Doc;
_mPdfViewCtrl?.CloseDoc();
_mPdfViewCtrl?.CloseTool();
_mPdfViewCtrl?.Destroy();
_mPdfViewCtrl = null;
_mPdfViewCtrl?.Dispose();
if (old_doc != null)
{
old_doc.Dispose();
}
if (old_tool != null)
{
old_tool.Dispose();
}
如果您的 Activity 也有对 PDFDoc 对象的引用,那么您也应该处理它。这是推荐的方式。
protected override void OnDestroy()
{
base.OnDestroy();
if (_mPdfViewCtrl == null) return;
_mPdfViewCtrl.Destroy();
_mPdfViewCtrl = null;
if(_mPdfDoc != null)
{
_mPdfDoc.Dispose();
}
}
或更普遍
protected override void OnDestroy()
{
base.OnDestroy();
if (_mPdfViewCtrl == null) return;
PDFDoc old_doc = _mPdfViewCtrl.Doc;
_mPdfViewCtrl.Destroy();
_mPdfViewCtrl = null;
if(old_doc != null)
{
old_doc.Dispose();
}
}
从这个link:
"问:我有一个用户选择文件的页面,另一个用户查看所选 PDF 的页面。当用户从 PDF 查看页面导航回文件页面时,我想清理使用的资源by PDFNet。清理工具、PDFViewCtrl 和 PDFDoc 的正确顺序是什么。
答:需要先调用PDFViewCtrl.CloseDoc(),然后才能调用PDFDoc.Dispose()。 对于使用 PDFViewCtrl 的任何页面,都可以放入 OnNavigatedFrom。
此外,PDFViewCtrl 不能手动处理,相反,我们添加了一个 PDFViewCtrl.FreeResources 来删除所有底层结构,这意味着在垃圾收集器启动之前使用的内存更少。
我想补充一下:
PDFDoc doc = this.PDFViewCtrl.GetDoc();
this.PDFViewCtrl.CloseDoc();
if (doc != null)
{
await CloseDocAsync(doc);
}
this.PDFViewCtrl.FreeResources();
CloseDocAsync 只是在后台线程中调用 doc.Dispose(如果它是一个大而复杂的文档)。这可能没有必要,因为我所知道的所有文件都会很快处理掉。但它不疼。 UI 线程即使延迟 200 毫秒也可能会造成破坏。
要记住的一件事是,为了让垃圾收集器回收 PDFViewCtrl,所有注册到它的事件都需要注销。这就是为什么当您离开页面时也应该调用 ToolManager.Dispose() 的原因。 在这种情况下,只需在我上面添加的任何代码之前调用 ToolManager.Dispose。"
如果上述 none 有帮助,您可以尝试在提供优先技术支持的 PDFTron forum. The company also has a tech support option 中重新发布您的问题。根据您使用的版本,技术支持可能是免费的。
编辑
我为文档提供的 links 是针对 Windows 版本的,而不是 Android。这是 PDFViewCtrl and PDFDoc.
的 Android 版本 link因此,我上面提供的 link 中的代码对您不起作用。您可能会尝试做的只是关闭文档。有一个 CloseDoc 方法可以从 PDFViewCtrl class 中调用。如果这不起作用,请尝试从 PDFDoc 方法调用 Close 方法。 PDFViewCtrl class 有一个名为 getDoc 的方法,它 returns 当前文档,它是一个 PDFDoc。文档说 PDFDoc.close 方法是一个析构函数。所以,试试这两个想法。
我注意到的另一件事是 PDFViewCtrl class 中有锁定和解锁方法。如果上述 2 个想法不起作用,您可以尝试在调用 close 方法之前调用 docUnlock 方法。这个想法是,如果文档被锁定,关闭调用可能会挂起或超时。
现在,如果 none 有效,那么您正在做的其他事情是否正在消耗内存?您或您团队中的其他人是否有可能忘记为您可能正在做的其他事情清理内存?是否有人使用 C++,或者可能使用 API,它在底层使用 C++ 并且忽略了删除内存,或者调用适当的关闭方法来正确清理?
使用探查器可能有助于回答这些问题。有第 3 方分析器可用,或者您可以尝试 Microsoft .NET Memory Analyzer。我不知道它是否会起作用 Android。它还需要 .NET Framework 4.5 或更高版本。
还有一个 Xamarin profiler,这可能是一个更好的开始选择。