PDFViewCtrl未处理

时间:2016-09-29 15:39:08

标签: c# memory-management xamarin.android pdftron

我们正在使用PDFTron开发应用。我们注意到,当打开显示已分配内存的Activity时,会大量增加。离开活动后,只有一部分内存被释放。一些PDFtron部件被遗忘。

enter image description here

问题是即使我们已将活动设置为NoHistory和singleTask,活动似乎也没有完成。我看了一些关于内存管理的课程,但无法弄清楚活动是什么原因让我们保持开放。

在我们调用活动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工作室监控): enter image description here

编辑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();
        }

enter image description here

2 个答案:

答案 0 :(得分:3)

从此link

“问:我有一个用户选择文件的页面,另一个用户查看所选PDF的页面。当用户从PDF查看页面导航回文件页面时,我想清理PDFNet使用的资源清理Tools,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。“

如果上述方法都不起作用,您可以尝试在PDFTron forum中重新发布您的问题。该公司还有一个tech support option,提供优先技术支持。根据您使用的版本,技术支持可能是免费的。

修改

我为文档提供的链接是针对Windows版本的,而不是针对Android的。以下是PDFViewCtrlPDFDoc的Android版链接。

所以,我上面给出的链接中的代码对你不起作用。您可能尝试做的只是关闭文档。有一个可以从PDFViewCtrl类调用的CloseDoc方法。如果这不起作用,那么尝试从PDFDoc方法调用Close方法。 PDFViewCtrl类有一个名为getDoc的方法,它返回当前文档,即PDFDoc。文档说PDFDoc.close方法是析构函数。所以,尝试这两个想法。

我注意到的另一件事是PDFViewCtrl类中有锁定和解锁方法。如果上述2个想法不起作用,您可以在调用close方法之前尝试调用docUnlock方法。想法是,如果文档被锁定,关闭的调用可能会挂起或超时。

现在,如果这些都不起作用,那么你还有什么其他事情可以扼杀记忆吗?您或您团队中的其他人是否有可能忘记为您可能正在做的其他事情清理内存?是否有人使用C ++,或者使用下面使用C ++的API而忽略了删除内存,或调用适当的close方法来正确清理?

使用分析器可以帮助回答这些问题。可以使用第三方分析器,或者您可以尝试Microsoft .NET Memory Analyzer。我不知道它是否适用于Android。它还需要.NET Framework 4.5或更高版本。

还有一个Xamarin profiler,这可能是一个更好的选择。

答案 1 :(得分:1)

如果您的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();
    }
}