1

我们正在开发一个使用 PDFTron 的应用程序。我们注意到,当打开显示分配内存的 Activity 时,会增加很多。离开活动后,只有一部分内存再次被释放。一些 PDFtron 部件被留下。

在此处输入图像描述

问题是,即使我们将活动设置为 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 Studio 监控): 在此处输入图像描述

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

在此处输入图像描述

4

2 回答 2

3

从这个链接

“问:我有一个用户选择文件的页面,还有一个用户查看所选 PDF 的页面。当用户从 PDF 查看页面导航回到文件页面时,我想清理 PDFNet 使用的资源。什么是清理工具、PDFViewCtrl 和 PDFDoc 的正确顺序。

A:您需要先调用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论坛中重新发布您的问题。该公司还有一个技术支持选项,可提供优先技术支持。根据您使用的版本,技术支持可能是免费的。

编辑

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

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

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

现在,如果这些都不起作用,那么您正在做的其他事情是在咀嚼记忆吗?您或您小组中的其他人是否有可能忘记为您可能正在做的其他事情清理内存?是否有人在使用 C++,或者可能使用在下面使用 C++ 的 API 并且忽略删除内存,或者调用适当的关闭方法来正确清理?

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

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

于 2016-10-04T06:24:26.263 回答
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();
    }
}
于 2016-10-03T17:41:23.943 回答