手机版 欢迎访问某某自媒体运营网(www.baidu.com)网站

当前位置: 主页 > 分析

游戏内存优化那点事

时间:2024-04-15 12:53|来源:网络|作者:佚名|点击:

注:摘取字节跳动开发者文档的图片资源使用注意事项和纹理内存优化头条文档

注:摘取微信开发者文档的运行性能优化

游戏运行时占用的内存大小,是衡量游戏性能的一个非常重要的指标。游戏如果占用的内存过大,会导致以下的问题:

1)发热,发烫。过多的内存数据传输,是导致游戏发热的主要原因之一。

2)延迟、卡顿。像纹理的加载、传输都需要耗费时间,另外内存资源占用的越多,系统也更加容易触发 gc 操作,导致游戏非预期卡顿。

3) 闪退。游戏超过一定的内存上限,操作系统会强制杀死进程。

js常见的内存泄漏:1. 意外的全局变量、2. 计时器和回调函数timers、3. js闭包、4. console、

5.引用计数管理时存在循环饮用的问题

使用Loading场景,保证上个场景释放占用的内存资源,再加载下一个场景

引用计数+自动释放池机制,在一帧内创建太多临时变量(让临时变量提前释放(手动释放货创建局部自动释放池)

垃圾回收机制中手动调用GC

生命周期比较短,个数较多,可能需要频繁创建、销毁,创建开销比较大的对象

下面左边的图片,一半的面积,都是透明部分,浪费大量的空间,在 UI 输出资源时应该尽量避免,或者用工具修剪掉透明部分。右边是修剪后的图片。尺寸由 750*375 变为 466*284,占用内存减小 50%。

当界面资源要显示的图片尺寸比较大,且中间部分是由连续有规则的像素组成时,通常使用九宫格拉伸的办法,大幅度减小图片尺寸的大小。对于可以进行拉伸的图片,划分成以下 9 个部分:

拉伸规则如下:

1)四个边角 1、3、7、9 不做任何拉伸

2)2、4、6、8 做单向拉伸,2、8 做横向拉伸,4、6 做纵向拉伸

3)5 做双向拉伸

下面的图片尺寸是 612*946,格式是 RGBA8888,如果使用九宫格拉伸的办法,那么尺寸可以做到小于 300*300,占用内存减小 80%以上。

像场景贴图、界面背景图等资源,占用内存比较大,但为了保证效果,不能去减小尺寸,这种情况下可以考虑使用压缩纹理。压缩纹理采用的是有损的压缩算法,一般效果都是可以接受的。下面是两张对比图:左边是 s3tc 格式的压缩纹理资源,右图是未压缩的图片资源。对比下两张资源图,大部分地方肉眼不容易识别出差别,左边图片在边缘细节上,要差一些(可以双击放大看)。

1)加载速度

压缩纹理>ccz或gc压缩的压缩纹理>pvr格式的非压缩纹理>png、jpeg>webp

2)内存(显存)暂用

3)压缩纹理优先

无alpha通道优先考虑RGB565,图片无半透明像素优先RGBA5551

4)显示效果基本和内存占用相反

5)文件大小

webp<jpeg<png8<png24<pvr.ccz/gz(pvrtc)<pkm.ccz/gz

/**
 * 资源管理
 * @see ResManager.ts 
 */

import PromiseUtil from "https://zhuanlan.zhihu.com/Utils/PromiseUtil";

export class ResManager{

    private static instance: ResManager;
    private resMap: Map<string, cc.Asset>=new Map()

    public static getInstance(): ResManager{
        if (this.instance==null){
            this.instance=new ResManager();
        }
        return this.instance;
    }


    /**
     * 加载资源
     * @param path 资源绝对路径
     * @returns 
     */
    public loadRes<T extends cc.Asset>(path, type?){
        return new Promise<T>((resolve, reject)=>{
            if (type){
                cc.resources.load(path, type, (error: Error, asset: T)=>{
                    if (error){
                        cc.error(error)
                        reject();
                    }
                    if (!asset) reject();
                    asset.addRef();
                    // cc.log('ResMgr==load==>', path, asset.refCount);
                    if (!this.resMap.get(path)) this.resMap.set(path, asset);
                    resolve(asset)
                });
            }else{
                cc.resources.load(path, (error: Error, asset: T)=>{
                    if (error){
                        cc.error(error)
                        reject();
                    }
                    if (!asset) reject();
                    asset.addRef();
                    // cc.log('ResMgr==load==>', path, asset.refCount);
                    if (!this.resMap.get(path)) this.resMap.set(path, asset);
                    resolve(asset)
                });
            }
        });
    }

    /**
     * 卸载资源(引用计数减1)
     * @param path 资源绝对路径
     */
    public releaseRes(path: string){
        let asset=this.resMap.get(path)
        if (asset && asset.refCount > 0){
            asset.decRef();
            // cc.log('ResMgr==release==>', path, asset.refCount);
            if (asset.refCount==0){
                this.resMap.delete(path);
            }
        }
    }

    /**
    * 强制卸载资源 
    * @param path 资源绝对路径
    */
    public forceReleaseRes(path: string){
        cc.resources.release(path);
    }

    /**
    * 加载目录资源
    * @param dirPath 
    */
    public loadDir(dirPath: string){
        let infos=cc.resources.getDirWithPath(dirPath);
        infos.map(async (info)=>{
            this.loadRes(info.path);
            await PromiseUtil.wait(0);
        });
    }

    /**
    * 卸载目录资源
    * @param dirPath 目录
    */
    public releaseDir(dirPath: string){
        let infos=cc.resources.getDirWithPath(dirPath);
        infos.map((info)=>{
            this.releaseRes(info.path);
        });
    }

    /**
    * 强制卸载目录资源 
    * @param path 资源绝对路径
    */
    public forceReleaseDir(dirPath: string){
        let infos=cc.resources.getDirWithPath(dirPath);
        infos.map((info)=>{
            this.forceReleaseRes(info.path);
        });
    }
}

Copyright © 2002-2022 首页-雷神娱乐电商新闻发布站 版权所有

平台注册入口