android - Sceneform - 如何修复泄漏的 SceneView?

标签 android arcore sceneform leakcanary

我已经使用 SceneView 加载 3D 模型将近一年了,但我一直不明白是什么导致了这种泄漏。我会实现 LeakCanary,但只有这一次泄漏,因为我不知道如何解决这个问题。

但现在我想弄清问题的根源并尝试解决它。我已经在 Sceneform 的两个版本上对其进行了测试——1.15.0 和被 Google 1.17.1 弃用之前的最后一个版本以及两个问题都会发生。

当您在 ActivityFragment 中使用 SceneView 加载模型时会发生泄漏(我都试过了)并且您“退出”通过执行 System home navigation 或通过 Recent tasks list 切换到不同的应用程序”。

enter image description here

泄漏日志:

┬───
│ GC Root: System class
│
├─ android.app.ActivityThread class
│    Leaking: NO (MainActivity↓ is not leaking and a class is never leaking)
│    ↓ static ActivityThread.sCurrentActivityThread
├─ android.app.ActivityThread instance
│    Leaking: NO (MainActivity↓ is not leaking)
│    mInitialApplication instance of android.app.Application
│    ↓ ActivityThread.mActivities
├─ android.util.ArrayMap instance
│    Leaking: NO (MainActivity↓ is not leaking)
│    ↓ ArrayMap.mArray
├─ java.lang.Object[] array
│    Leaking: NO (MainActivity↓ is not leaking)
│    ↓ Object[].[1]
├─ android.app.ActivityThread$ActivityClientRecord instance
│    Leaking: NO (MainActivity↓ is not leaking)
│    activity instance of com.example.a3dmodeltester.MainActivity with
│    mDestroyed = false
│    ↓ ActivityThread$ActivityClientRecord.activity
├─ com.example.a3dmodeltester.MainActivity instance
│    Leaking: NO (SceneView↓ is not leaking and Activity#mDestroyed is false)
│    mApplication instance of android.app.Application
│    mBase instance of android.app.ContextImpl
│    ↓ MainActivity.sceneView
├─ com.google.ar.sceneform.SceneView instance
│    Leaking: NO (View attached)
│    View is part of a window view hierarchy
│    View.mAttachInfo is not null (view attached)
│    View.mID = R.id.sceneview
│    View.mWindowAttachCount = 1
│    mContext instance of com.example.a3dmodeltester.MainActivity with
│    mDestroyed = false
│    ↓ SceneView.renderer
│                ~~~~~~~~
├─ com.google.ar.sceneform.rendering.Renderer instance
│    Leaking: UNKNOWN
│    Retaining 2.9 kB in 38 objects
│    ↓ Renderer.viewAttachmentManager
│               ~~~~~~~~~~~~~~~~~~~~~
├─ com.google.ar.sceneform.rendering.ViewAttachmentManager instance
│    Leaking: UNKNOWN
│    Retaining 2.2 kB in 19 objects
│    ↓ ViewAttachmentManager.frameLayout
│                            ~~~~~~~~~~~
╰→ android.widget.FrameLayout instance
​     Leaking: YES (ObjectWatcher was watching this because android.widget.
​     FrameLayout received View#onDetachedFromWindow() callback)
​     Retaining 1.9 kB in 15 objects
​     key = 10550463-895e-443a-898f-11c5131da209
​     watchDurationMillis = 5165
​     retainedDurationMillis = 157
​     View not part of a window view hierarchy
​     View.mAttachInfo is null (view detached)
​     View.mWindowAttachCount = 1
​     mContext instance of com.example.a3dmodeltester.MainActivity with
​     mDestroyed = false

METADATA

Build.VERSION.SDK_INT: 27
Build.MANUFACTURER: Google
LeakCanary version: 2.7
App process name: com.example.a3dmodeltester
Stats: LruCache[maxSize=3000,hits=892,misses=24408,hitRate=3%]
RandomAccess[bytes=1232425,reads=24408,travel=6462427001,range=8963521,size=1161
0814]
Heap dump reason: 1 retained objects, app is not visible
Analysis duration: 5411 ms

重现泄漏:

弃用前的最后一个版本:

 implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.17.1'
 debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'

我也用 1.15.0 试过了

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <com.google.ar.sceneform.SceneView
        android:id="@+id/sceneview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"/>
</RelativeLayout>

MainActivity(也测试了 fragment )

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private static final Vector3   STARTING_CAMERA_POSITION = new Vector3(0f, 1f, 3f);
    private              SceneView sceneView;
    private              Node      node;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sceneView = findViewById(R.id.sceneview);
        Scene scene = sceneView.getScene();
        node = new Node();
        scene.addChild(node);

        ModelRenderable.builder()
                .setSource(this, Uri.parse("Andy.sfb"))
                .build()
                .thenAccept(renderable -> node.setRenderable(renderable))
                .exceptionally(
                        throwable -> {
                            Log.e(TAG, "Unable to load Renderable.", throwable);
                            return null;
                        });
        Camera camera = scene.getCamera();
        camera.setWorldPosition(STARTING_CAMERA_POSITION);
    }

    @Override
    public void onPause() {
        super.onPause();
        sceneView.pause();
    }

    @Override
    public void onResume() {
        super.onResume();
        try {
            sceneView.resume();
        } catch (CameraNotAvailableException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        sceneView.destroy();
    }
}

.sfb 文件

enter image description here

https://drive.google.com/file/d/1NchJ2NGNM7NZzRZkq4fewALc7m4dnGG3/view?usp=sharing

要重现,请在 SceneView 运行时按 HomeRecent task list 按钮

enter image description here

我也仅使用 SceneView 对其进行了测试,但它也会泄漏。

enter image description here

我该如何解决这个漏洞?

我还在多个 API、模拟器和真实设备上对其进行了测试,并且它发生在所有这些设备上。

最佳答案

我已经尝试了这些选项来阻止泄漏,但它们没有做任何事情:

Scene scene = sceneView.getScene();
scene = null;
sceneView = null;
sceneView.destroy();
Renderer.destroyAllResources();
Renderer.reclaimReleasedResources();

然而,这为我修复了漏洞:

中删除sceneView.pause();
@Override
public void onPause()

在执行系统主页导航或通过“最近的任务”列表切换到其他应用程序时停止泄漏。 (OP中的问题)

添加 sceneView.pause();

@Override
public void onDestroy()

防止 Activity 或 fragment 被销毁时发生泄漏。

    @Override
    public void onDestroy() {
        super.onDestroy();
        sceneView.pause(); 
    }

关于android - Sceneform - 如何修复泄漏的 SceneView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71087417/

相关文章:

java - 在 Android 上使用 REST 服务,最简单的方法?

android - 搜索 ListView 标志的功能 - 无法解析方法“getFilter()”

java - 将图像从对话框拖放到 Activity 时出现问题

java - Sceneform ARCore 加载并构建随机 3D 资源

android - 使用 Sceneform 生态系统有问题地旋转 3D 模型

android - android中的Sqlite更改数据类型

swift - ARKit – 使用世界射线而不是屏幕点进行光线转换

android - Unity ARCore 对象跟踪和移动问题

c# - 一旦 ARCore 在 Unity 应用程序中加载,文本就会消失

java - 如何在 scenform 中将模型旋转到另一个模型?