UE4常驻内存

转自:https://dawnarc.com/2017/04/ue4%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E4%B8%8E%E5%86%85%E5%AD%98%E5%B8%B8%E9%A9%BB/

防止GC的办法

一个UObject类型的变量,即使是static,默认也会被GC掉。

要防止该对象被GC,有4种方式:

  • 作为成员变量并标记为UPROPERTY()
  • 创建对象后 AddToRoot() ;(退出游戏时需要RemoveFromRoot()
  • FStreamableManager Load资源时,bManageActiveHandle 设置为true;
  • FGCObjectScopeGuard 在指定代码区域内保持对象;

Uobject不能使用TSharedPtr进行引用计数,非UObject才可以;如果一个非UObject的类想加入GC,那么必须继承FGCObject类。

UPROPERTY()用法
URPOPERTY()
    UObject* MyObj;

AddToRoot()用法
UMyObject* MyObj = NewObject<UMyObject>();
MyObj.AddToRoot();

FStreamableManager 用法
FSoftObjectPath AssetPath(TEXT("/Game/Mannequin/Animations/ThirdPersonWalk.ThirdPersonWalk"));
FStreamableManager& AssetLoader = UAssetManager::GetStreamableManager();

//hold object in memory.
TSharedPtr<FStreamableHandle> Handle = AssetLoader.RequestSyncLoad(AssetPath, true);
UObject* Obj = Handle->GetLoadedAsset();

//free memory of object.
Handle->ReleaseHandle();

FGCObjectScopeGuard 用法
{
    FGCObjectScopeGuard(UObject* GladOS = NewObject<...>(...));
    GladOS->SpawnCell();
    RunGC();
    GladOS->IsStillAlive();   // Object will not be removed by GC
}

GC 常见问题
  1. 官方论坛上有人说 NewObject() 或者 LoadObject() 创建的对象才会自动被 GC , SpawnActor 创建的对象会被自动 AddToRoot ,不会被 GC。不知早期的版本是否确实如此,但是目前版本不是这样,即使是 SpawnActor ,默认也会被 GC。
参考资料

虚幻4垃圾回收剖析
http://www.cnblogs.com/ghl_carmack/p/6112118.html

转载:UE4内存管理 – 实践
http://blog.csdn.net/yangxuan0261/article/details/52075581

原文内容如下:

UObject gc机制

  • 通过 UPROPERTY() 去保持引用

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyChar")
    class UBehavData* mBehavData;
    
    mBehavData = NewObject<UBehavData>(this, UBehavData::StaticClass());
    bh->mId = 111;
    
    
  • TArray保持引用如果有个 TArray 容器,则这个TArray需要用一个UPROPERTY() 去保持容器的引用,然后里面的UObject就不需要再去AddToRoot去阻止被gc了。

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UCoolDownComponent")
    TArray<UCoolDown*>      mCDArr;
    
    UCoolDown* cd = NewObject<UCoolDown>(_class);
    cd->SetSkillId(_skillId);
    mCDArr.Add(cd);
    
    

    容器clear后,元素会自动被gc

  • 4.15版本支持了蓝图 TMap 容器,也是可以通过 UPROPERTY()去保持容器的引用,容器内的UObject就不需要再去AddToRoot去阻止被gc了

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyChar")
        TMap<int32, UBehavData*> mTestMap2;
    
    UBehavData* bh = NewObject<UBehavData>(this, UBehavData::StaticClass());
    bh->mId = 111;
    mTestMap2.Add(111, bh);
    bh = NewObject<UBehavData>(this, UBehavData::StaticClass());
    bh->mId = 222;
    mTestMap2.Add(222, bh);
    
    
  • 没有任何容器保持引用需要AddToRoot添加标记去阻止被gc

    m_sInstance = NewObject<T>();
    m_sInstance->AddToRoot();
    
    

    让对象重新被gc回收,需要移除标记(不是立即释放对象,是在某个时间gc时才释放对象)

    m_sInstance->RemoveFromRoot();
    m_sInstance = nullptr;
    
    
  • c++ new对象丢个蓝图引用住防止gc

    c++ new对象

    UFUNCTION(BlueprintPure, Category = "UBehavData")
    static UBehavData* CreateBehavData();
    
    UBehavData * UBehavData::CreateBehavData()
    {
        UBehavData* behavData = (UBehavData*)NewObject<UBehavData>(UBehavData::StaticClass());
        return behavData;
    }
    
    

    蓝图 第一时间 用一个变量 mBehavData 引用住,就可以防止这个对象被gc掉。切记第一时间。

    image

    将蓝图中的变量 mBehavData 设为 null,则对象会被gc不定时回收掉

    image
  • 强制gc

    GWorld->GetWorld()->ForceGarbageCollection(true);
    
    

AActor gc机制

一般重写这两个函数,来做一些初始化和清理工作

virtual void PostActorCreated() override; //做初始化工作
virtual void BeginPlay() override; //做初始化工作
virtual void BeginDestroy() override; //引擎在gc的时候调用,并不是立即调用,一般不用
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; //做清理工作
virtual void Destroyed() override; //用于释放成员,调用Destroy();会立即调用

调用SpawnActor或DestroyActor会调用到这两个函数,析构函数则要在gc的时候才会调用,可以调用gc函数测试一下

GWorld->GetWorld()->ForceGarbageCollection(true);

UActorComponent gc机制

  • 作为Actor的组件存在于Actor的组件列表中,销毁Actor时会把组件列表遍历一边destroy掉并标记为待gc的对象,在一个不定时的时间被gc掉

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyChar")
    UCoolDownComponent*     mCDComp;    //注册cd组件
    
    
  • 任意时刻销毁,即使宿主Actor未被销毁C++销毁则直接调用接口

    void UActorComponent::DestroyComponent(bool bPromoteChildren/*= false*/)
    
    

    蓝图销毁,需要设置一个UActorComponent的属性

        bAllowAnyoneToDestroyMe = true;
    
    

    因为提供给蓝图的接口需要判断这个字段,默认是false

    UFUNCTION(BlueprintCallable, Category="Components", meta=(Keywords = "Delete", HidePin="Object", DefaultToSelf="Object", DisplayName = "DestroyComponent"))
    void K2_DestroyComponent(UObject* Object);
    
    void UActorComponent::K2_DestroyComponent(UObject* Object)
    {
        AActor* MyOwner = GetOwner();
        if (bAllowAnyoneToDestroyMe || Object == this || MyOwner == NULL || MyOwner == Object)
        {
            DestroyComponent();
        }
        else
        {
            // TODO: Put in Message Log
            UE_LOG(LogActorComponent, Error, TEXT("May not destroy component %s owned by %s."), *GetFullName(), *MyOwner->GetFullName());
        }
    }
    
    
  • 一般重写这两个函数,来做一些初始化和清理工作

    // Begin UActorComponent Interface.
    virtual void BeginPlay() override; //组件RegisterComponent注册的时候,且有OwnerActor才会立即调用,一般不用
    virtual void BeginDestroy() override; //引擎在gc的时候调用,并不是立即调用,一般不用
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; //立即调用,一般这里做清理工作(注册过才会调用),且gc时还会再调用一次,一般不用
    virtual void OnComponentCreated() override; //组件RegisterComponent注册的时候立即调用,一般这里做初始化工作
    virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;//立即调用,一般这里做清理工作(只要DestroyComponent就会调用)
    
    // End UActorComponent Interface.
    
    

    默认的gc是时间测试得到为1min 如果需要立即销毁,使用这个接口

    mCDComp->DestroyComponent(); //会立即调用到 OnComponentDestroyed,并标记为准备被gc回收
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容