Unity内存优化(-)托管堆ManagedHeap的优化

很多童鞋在进行内存分析的时候都会遇到下面的问题:


ManagedHeap.UsedSize和ManagedHeap.reservedUnUsedSize这两个占用了很大内存,即使手动GC.Collect之后,ManagedHeap.UsedSize和ManagedHeap.reservedUnUsedSize两者的综合仍然没有发生变化,内存占用依然没有缓解。

在分析内存时,也发现了相同的问题。之前的数据表是用Json格式存储的,数据表比较大将近30M,当读取到内存的时候出现了上面的情况。

这是为什么呢?首先,我们要了解几个概念:

  • ManagedHeap 表示的是Mono所使用的托管堆内存,C#上任何的申请托管的内存都会在这个上面申请。
  • ManagedHeap.UsedSize 表示这个托管堆上已经使用的内存大小
  • ManagedHeap.reservedUnUsedSize 表示托管堆上未使用的内存大小

当我们申请内存时,如果ManagedHeap.reservedUnUsedSize的内存不够用,Mono会向os申请内存。并且这个内存会扩大ManagedHeap的大小,并且这个内存不会回落。

我们可以通过Profiler.GetMonoHeapSize()获取Mono堆上的总内存和mono_gc_get_heap_size是一个意思。

下面写了一个测试用例:

using UnityEngine;
using System;
using System.Runtime.InteropServices;
using System.Text;
 
public class TestManagedHeap : MonoBehaviour
{
    public int arraysize = 1024 * 1024 * 200;//条件触发延迟申请的内存1
    public int arraysize_frame = 1024 * 1024 * 10;//条件触发延迟申请的内存2
 
    [DllImport("mono.dll")]
    public static extern long mono_gc_get_used_size();
    [DllImport("mono.dll")]
    public static extern long mono_gc_get_heap_size();
 
    //private StringBuilder builder = new StringBuilder(256);
    // Use this for initialization
    void Start()
    {
    }
 
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.U))
        {
            byte[] array = new byte[arraysize];
            array = null;
            Debug.Log("申请200M");
            printMemory();
        }
        if (Input.GetKeyDown(KeyCode.A))
        {
            byte[] array = new byte[arraysize_frame];
            Debug.Log("申请10M");
            printMemory();
        }
        if (Input.GetKeyDown(KeyCode.B))
        {
            Debug.Log("调用GC");
            GC.GetTotalMemory(true);
            printMemory();
        }
    }
 
    void printMemory()
    {
        long usedsize = mono_gc_get_used_size();
        long heapsize = mono_gc_get_heap_size();
        long reservedsize = heapsize - usedsize;
        builder.Length = 0;
        //builder.AppendFormat("使用内存:{0},剩余内存{1},托管堆内存{2}",usedsize,reservedsize,heapsize);
        //print(builder.ToString());
    Debug.Log("使用内存=" + usedsize * 1.0f / 1024 / 1024 + "M");
     Debug.Log("剩余内存=" + reservedsize * 1.0f / 1024 / 1024 + "M");
    Debug.Log("托管堆内存=" + heapsize * 1.0f / 1024 / 1024 + "M");
 }

Memory is allocated in heap blocks. More can allocated if it cannot fit the data into the allocated block. Heap blocks will be kept in Mono until the app is closed. In other words, Mono does not release any memory used to the OS (Unity 3.x). Once you allocate a certain amount of memory, it is reserved for mono and not available for the OS. Even when you release it, it will become available internally for Mono only and not for the OS. The heap memory value in the Profiler will only increase, never decrease.

 上面是摘自Unity官方API对Profiling对Mono Memory的解释。

鉴于这个原因,在app开发时需要注意什么呢?

  1. 不要一次性申请过大的内存;
  2. 切换场景等操作时可以自己手动调用GC.Collec

原文地址:http://www.showxyz.com/?p=96

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值