j***@hotmail.com
j***@hotmail.com
  • 发布:2025-05-07 07:29
  • 更新:2025-05-07 07:29
  • 阅读:77

【报Bug】使用video循环播放视频,内存溢出。

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: windows 11

HBuilderX类型: 正式

HBuilderX版本号: 4.36

手机系统: Android

手机系统版本号: Android 5.1

手机厂商: 华为

手机机型: 工业机主板

页面类型: vue

vue版本: vue3

打包方式: 云端

项目创建方式: HBuilderX

示例代码:
<template> <view> <video id="pageVideo" @ended="handleVideoEnd" @error="handleVideoError" :src="videoUrl" autoplay="true" controls="false" :show-play-btn="false" :show-center-play-btn="false" :enable-play-gesture="false" page-gesture="false" codec="software" v-if="showVideo"> <cover-view class="cover-container">
<cover-image :src="imageUrl" :id='pageImageId'></cover-image>
<cover-image class="uniLogo1" src="/static/logo.png" @click="logoClick"></cover-image>
<cover-image class="uniLogo2" src="/static/machineLogo.jpg" @click="machineLogoClick"></cover-image>
</cover-view>
</video>
</view>
<view>
<text>内容描述:{{dynamicText}}</text>
</view>
<view>
<text>点击的图片:{{imageClick}}</text>
</view>
<view>
<text>我是信息提示:{{showTips}}</text>
</view>
<view>
<text>最大内存:{{maxMemory}},其它内存信息{{memoryInfo}}</text>
</view>
</template>

<script>
export default {
data() {
return {
showVideo: true,
showTips: '',
dynamicText: '',
imageClick: '',
myArray: [],
startIndex: 0,
videoUrl: '',
imageUrl: '',
videoCtx: null, // 用于保存video上下文,
timeSpan: 3000,
pageImageId: '',
videoKey: false,
gcCount: 0,
clearTimer: null,
memoryTimer: null,
memoryInfo: '',
maxMemory: 0,
}
},
onLoad() {},
onReady() {
this.myArray = [
//'/static/tp.png',
'/static/2.mp4',
//'/static/banner.png',
// '/static/1.mp4',
// '/static/2.mp4',
// '/static/1.mp4',
// '/static/2.mp4',
// '/static/1.mp4',
// '/static/2.mp4',
// '/static/1.mp4',
// '/static/2.mp4',
// '/static/1.mp4',
// '/static/2.mp4',
// '/static/1.mp4',
// '/static/2.mp4',
// '/static/1.mp4',
// '/static/2.mp4',
// '/static/1.mp4',
// '/static/2.mp4',
];
var length = this.myArray.length;
//从视频数组中娶最后一个,初始化后,播放视频时,从数组里第一个开始播
this.startIndex = length - 1;
this.dynamicText = "myArray里放了" + length + "个视频,3秒后开始播放视频";
//this.getMemoryInfo();
//this.startTimer();
this.playVideo();
},
methods: {
getMemoryInfo() {
this.memoryTimer = setInterval(() => {
if (plus.os.name === 'Android') {
const Runtime = plus.android.importClass('java.lang.Runtime');
const runtime = Runtime.getRuntime();
const usedMB = ((runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)).toFixed((
2));
if (usedMB > this.maxMemory) {
this.maxMemory = usedMB;
}
this.memoryInfo = "[内存监控] 使用中: " + usedMB + "MB";
}
}, 1000);
},
startTimer() {
this.clearTimer = setInterval(() => {
//执行GC
this.clearMem();
}, 10000);
},
stopTimer() {
if (this.clearTimer) {
clearInterval(this.clearTimer);
this.clearTimer = null;
}
if (this.memoryTimer) {
clearInterval(this.memoryTimer);
this.memoryTimer = null;
}
},
// 初始化video上下文
initVideoContext() {
if (!this.videoCtx) {
this.videoCtx = uni.createVideoContext('pageVideo', this);
}
},
logoClick() {
this.imageClick = '绿色绿色绿色绿色绿色绿色绿色的图片';
},
machineLogoClick() {
this.imageClick = '白色白色白色白色白色白色白色的图片';
},
//视频播放
playVideo() {
//this.startIndex = this.startIndex + 1;
// if (this.startIndex > this.myArray.length - 1) {
// this.startIndex = 0;
// }
var url = this.myArray[0];
this.dynamicText = "现在播放的视频index是" + this.startIndex;
this.pageImageId = 'pageImageIdHidden';
this.showTips = '现在播放的是视频:' + url;

            this.initVideoContext();  

            setTimeout(() => {  
                this.showVideo = true; // 重建组件(强制释放内存)  
                this.videoUrl = url;  
                this.videoCtx.play();  
                this.startIndex = this.startIndex + 1;  
            }, 100);  

            // //执行GC  
            // this.clearMem();  

        },  
        clearMem() {  
            // 安卓原生代码(需封装为UniPlugin)  
            if (plus.os.name === 'Android') {  
                const System = plus.android.importClass('java.lang.System');  
                plus.android.invoke(this.videoCtx, 'release');  
                System.gc();  
                System.runFinalization();  

                if (plus.os.name === 'Android') {  
                    const Runtime = plus.android.importClass('java.lang.Runtime');  
                    const runtime = Runtime.getRuntime();  
                    const usedMB = ((runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024)).toFixed((  
                        2));  
                    // if (usedMB > this.maxMemory) {  
                    //  this.maxMemory = usedMB;  
                    // }  
                    // this.memoryInfo = "[内存监控] 使用中: " + usedMB + "MB";  
                    this.gcCount += 1;  
                    this.imageClick = "执行了GC" + this.gcCount + ',后内存大小为' + usedMB + "MB";  
                }  

            }  
        },  
        handleVideoEnd() {  
            try {  
                this.dynamicText = '视频正常播放结束,3秒后开始下一个视频';  
                this.videoCtx.pause();  
                this.videoCtx.stop();  
                this.videoCtx.seek(0);  
                this.videoUrl = ''; // 清除数据绑定  
                this.videoCtx = null;  
                // 先销毁再重新创建  
                this.showVideo = false;  
                this.clearMem();  
                setTimeout(() => {  
                    this.$nextTick(() => {  
                        this.playVideo();  
                    });  
                }, 3000);  
            } catch (e) {  
                this.dynamicText = e;  
            }  
        },  
        handleVideoError(e) {},  
    }  
}  

</script>
<style>
/ 页面样式 /
page {
hardware-accelerated: false;
}

.cover-container {  
    position: relative;  
    width: 100%;  
    height: 100%;  
}  

.uniLogo1 {  
    position: absolute;  
    width: 120rpx;  
    height: 60rpx;  
    bottom: 10%;  
    left: 10%;  
}  

.uniLogo2 {  
    position: absolute;  
    width: 120rpx;  
    height: 60rpx;  
    bottom: 10%;  
    right: 10%;  
}  

#pageVideo {  
    width: 100%;  
    height: 100px;  
}  

#pageImageId {  
    position: absolute;  
    width: 100%;  
    height: 100%;  
    top: 0%;  
    left: 0%;  
}  

#pageImageIdHidden {  
    position: absolute;  
    width: 100%;  
    height: 100%;  
    top: 0%;  
    left: 0%;  
    display: none;  
}  

</style>

操作步骤:

1.循环播放本地视频(测试时使用的同一个视频)。

  1. 在 ended 内 秒执行一次内存抛出,详细见代码示例内的 clearMem();中间执行了 v-if。抛出内存后3秒执行循环播放。设置了runmode为 liberate。
    3.抛出内存后,监控显示内存被释放,再次播放视频后,占用的内存峰值要大于前一次内存峰值。

预期结果:

循环播放同一个视频时,抛出内存后,内存占用峰值不应该越来越高。

实际结果:

抛出内存后,监控显示内存被释放,再次播放视频后,占用的内存峰值要大于前一次内存峰值。

bug描述:

android 5.1.1,循环播放本地视频,抛出内存,执行v-if,设置runmode为liberate。应用程序内存一直增加。
单次播放视频后停止所有执行动作,内存占用几乎不变,继续播放视频,内存占用会越来越大。

本地测试,第一次执行最高占用大概是126,GC后的内存是12左右。每次播放完执行GC计数加1,执行175次后,占用内存为195.97或者更高,GC的涨到44.73。
第一次写 uniapp 的项目,不太清除是不是代码逻辑上出的问题。

2025-05-07 07:29 负责人:无 分享
已邀请:

要回复问题请先登录注册