unity www在android端不释放内存问题解决方案

针对Unity游戏项目在Android平台上的内存占用问题,本文介绍了一种使用原生Java替代C#进行资源解压的方法,有效降低内存消耗并提高解压速度。通过对比分析,揭示了C#与Java在内存管理上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在优化unity游戏项目(android)内存占用,游戏打开时会先从包里的zip文件中解压一部分资源到本地,原本是使用的www进行解压,解压的包体有400M,解压完毕后发现unity竟然不会释放这部分内存给系统,而是继续持有.

查询了很多相关资料后发现这是C#的设计理念,应用如果可以成功申请到400M的内存进行解压,那这400M内存不会还给系统,而是被系统标记为空闲,后续如果要申请其它内存,会复用之前申请的这400M内存空间,减少数据吞吐提升运行效率,可是经实测发现,后续申请的内存并没有复用这400M,而是另外开辟了别的内存空间,这就无法接受了.

在试了很多办法无果后,决定抛弃C#,拥抱原生java吧,随即用java重新写了一个解压逻辑,没想到解压速度比c#还快很多,再辅以线程的帮助,解压时的loading动画也顺畅了很多,一举两得:

下面给出代码,一个是从apk包里解压文件,一个是从obb包里解压文件(如果采用obb分包,读取文件的路径略有不同)

public void unzipFromApk(Context context, String filePath) {
        new Thread(new Runnable(){

            @Override
            public void run(){
                String destination = getExternalFilesDir("StreamingAssets").getAbsolutePath();
                //String destination2 = getExternalFilesDir("").getAbsolutePath() + "/StreamingAssets/";

                Log.d("Unzip", "destination = " + destination);
                //Log.d("Unzip", "destination2 = " + destination2);

                try {
                    //FileInputStream inputStream = new FileInputStream(filePath);
                    ZipInputStream zipStream = new ZipInputStream(context.getAssets().open(filePath));
                    ZipEntry zEntry = null;
                    String szName = "";

                    while ((zEntry = zipStream.getNextEntry()) != null) {
                        Log.d("Unzip", "Unzipping " + zEntry.getName() + " at "
                                + destination);
                        szName = zEntry.getName();
                        if (zEntry.isDirectory()) {
                            szName = szName.substring(0, szName.length() - 1);
                            String folderName = destination + File.separator + szName;
                            File folder = new File(folderName);
                            folder.mkdirs();
                            zipedFileNum++;
                        } else {
                            String fileName = destination + File.separator + szName;
                            File file = new File(fileName);
                            if (!file.exists()) {
                                //Log.e(TAG, "Create the file:" + outPathString + File.separator + szName);
                                file.getParentFile().mkdirs();
                                file.createNewFile();
                            }

                            FileOutputStream fout = new FileOutputStream(fileName);
                            BufferedOutputStream bufout = new BufferedOutputStream(fout);
                            byte[] buffer = new byte[1024];
                            int read = 0;
                            while ((read = zipStream.read(buffer)) != -1) {
                                bufout.write(buffer, 0, read);
                            }

                            zipedFileNum++;

                            zipStream.closeEntry();
                            bufout.close();
                            fout.close();
                        }
                    }
                    zipStream.close();
                    Log.d("Unzip", "Unzipping complete. path :  " + destination);
                } catch (Exception e) {
                    Log.d("Unzip", "Unzipping failed");
                    e.printStackTrace();
                }
            }

        }).start();
    }

    public void unzipFromObbFile(Context context, String filePath) {
        new Thread(new Runnable(){

            @Override
            public void run(){
                String destination = getExternalFilesDir("StreamingAssets").getAbsolutePath();

                try {
                    //获取Obb扩展文件路径
                    String path = getObbDir().getPath() + "/main." +getVersionCode(MainActivity.this) + "." + getAppPackageName(MainActivity.this) + ".obb";
                    //得到obb文件实例
                    ZipResourceFile expansionFile = new ZipResourceFile(path);
                    //读取
                    InputStream inputStream = expansionFile.getInputStream("assets/" + filePath);

                    if (inputStream == null)
                    {
                        Log.d("Unzip", "zip file not found in assets");
                        inputStream = expansionFile.getInputStream(filePath);
                    }
                    else
                    {
                        Log.d("Unzip", "zip file found in assets!");
                    }

                    //FileInputStream inputStream = new FileInputStream(filePath);
                    ZipInputStream zipStream = new ZipInputStream(inputStream);
                    ZipEntry zEntry = null;
                    String szName = "";

                    while ((zEntry = zipStream.getNextEntry()) != null) {
                        Log.d("Unzip", "Unzipping " + zEntry.getName() + " at "
                                + destination);
                        szName = zEntry.getName();
                        if (zEntry.isDirectory()) {
                            szName = szName.substring(0, szName.length() - 1);
                            String folderName = destination + File.separator + szName;
                            File folder = new File(folderName);
                            folder.mkdirs();
                            zipedFileNum++;
                        } else {
                            String fileName = destination + File.separator + szName;
                            File file = new File(fileName);
                            if (!file.exists()) {
                                //Log.e(TAG, "Create the file:" + outPathString + File.separator + szName);
                                file.getParentFile().mkdirs();
                                file.createNewFile();
                            }

                            FileOutputStream fout = new FileOutputStream(fileName);
                            BufferedOutputStream bufout = new BufferedOutputStream(fout);
                            byte[] buffer = new byte[1024];
                            int read = 0;
                            while ((read = zipStream.read(buffer)) != -1) {
                                bufout.write(buffer, 0, read);
                            }

                            zipedFileNum++;

                            zipStream.closeEntry();
                            bufout.close();
                            fout.close();
                        }
                    }
                    zipStream.close();
                    inputStream.close();
                    Log.d("Unzip", "Unzipping complete. path :  " + destination);
                } catch (Exception e) {
                    Log.d("Unzip", "Unzipping failed");
                    e.printStackTrace();
                }
            }

        }).start();
    }

下面是我在搜寻解决方案时查到的一些相关资料,也是unity申请内存后不释放的类似问题:
https://forum.unity.com/threads/big-byte-array-will-cause-memory-leak.403496/

https://answers.unity.com/questions/225460/big-arrays-are-never-garbage-collected-why.html?_ga=2.57270627.890478631.1572264787-375802978.1561963564

参考资源链接:[UnityAndroid/iOS内存监控插件:实时查看真机内存](https://wenku.csdn.net/doc/2430q5sfap?utm_source=wenku_answer2doc_content) 监控移动设备内存使用情况是保证应用性能的关键。为了帮助你更好地掌握这一技巧,我推荐查看这份资料:《UnityAndroid/iOS内存监控插件:实时查看真机内存》。这份资源将为你提供实用的插件使用方法和实例,直接关联到你当前的问题。 在Unity中,使用内存监控插件能够实时获取Android和iOS设备的内存使用数据。首先,确保你的移动设备已经开启USB调试模式,并通过USB线连接到电脑。然后,在Unity编辑器中安装并导入内存监控插件。 插件将提供一个界面,显示连接设备的内存使用情况。你可以查看详细的内存使用表,包括堆内存、总内存和可用内存等信息。这些数据帮助你识别内存泄漏,优化内存分配,并对性能瓶颈作出及时响应。 在监控内存的同时,你可以利用Unity Profiler等工具来进一步分析应用的性能问题。此外,合理利用资源管理技巧,比如适时释放未使用的资源,避免内存泄漏,以及使用Unity的异步加载机制来优化资源加载,这些都有助于提升应用性能。 理解这些基础概念和操作后,你将能够更加高效地监控和管理Unity应用的内存使用,为用户提供流畅的体验。如果你希望深入了解更多关于内存管理、性能优化以及跨平台开发的知识,我建议继续学习《UnityAndroid/iOS内存监控插件:实时查看真机内存》。这份资料仅提供了问题的直接解决方案,还覆盖了相关领域的深入知识,助力你在移动开发的道路上断前进。 参考资源链接:[UnityAndroid/iOS内存监控插件:实时查看真机内存](https://wenku.csdn.net/doc/2430q5sfap?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值