I am reading wav files from external paths as USoundWave object. However I am not sure if everything disposed correctly. I could not be sure if this code will cause any memory leak.
My questions are:
Can you please inform me about this ?
How can I have idea about if that is causing memory leaks ?
NOTE:
When I stop/exit game and re-debug in engine (note that engine is still open) and I see increasing numeric array like :
SoundWave1 …SoundWave5 …SoundWave20 so on.
This made me think about code cause memory leaks.
// Fill out your copyright notice in the Description page of Project Settings.
#include "ReadWrite.h" //the other file for BP func. lib. ReadWrite is projects name
#include "SoundWave.h"
#include <FileManagerGeneric.h>
#include <Runtime/Engine/Classes/Sound/SoundWave.h>
#include <Runtime\Core\Public\Misc\FileHelper.h>
bool UReadWrite::ReadDir2(FString TestDir, TArray<FString>& OutFiles, TArray<UObject*>& OutSoundWaves, FString ext)
{
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true);
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
// Directory Exists?
if (!PlatformFile.DirectoryExists(*TestDir))
{
//PlatformFile.CreateDirectory(*TestDir);
if (!PlatformFile.DirectoryExists(*TestDir))
{
return false;
}
}
else
{
const TCHAR* searchDir=*TestDir;
const TCHAR* fileExt=*ext;
PlatformFile.FindFiles(OutFiles, searchDir, fileExt);
if (OutFiles.Num() > 0) {
for (int i=0; i < (OutFiles.Num()); i++)
{
OutSoundWaves.Add(GetSoundWaveFromFile(OutFiles*));
}
}
}
return true;
}
Basically, as long as some field that is marked as a UPROPERTY is pointing to your UObject (whether it’s contained in an TArray/Container, or a “raw” UObject* ), that object will be kept alive. As soon as those references all disappear (you clear the array, or set the pointer you had to nullptr or some other object) - the GC system will see that object has no more references and will mark it for delete.
UCLASS()
class MyActor : public AActor
{
// ...
void AddFriends(MyActor* MyNewFriend);
void RemoveFriends();
UPROPERTY()
MyActor* LatestFriend; // SAFE: Any MyActor that I point to will be kept alive because I own a reference.
UPROPERTY()
TArray<MyActor*> MyFriendHistory; // SAFE: All the actors contained within this container will be kept alive, again - I own the reference.
MyActor* MyDangerousFriend; // NOT SAFE: The UE GC system is unable to track this pointer because it's not a UPROPERTY, any value pointed to this may be invalid at any point.
}
void MyActor::AddFriend(MyActor* MyNewFriend)
{
if (LatestFriend) // If we already have a friend, let's save them off to a list.
{
MyFriendHistory.AddItem(LatestFriend); // Store our old friend, the object won't be cleaned up because we still own a reference through this container.
}
LastestFriend = MyNewFriend; // All good. MyNewFriend will not be cleaned up.
}
void MyActor::RemoveFriends()
{
LatestFriend = nullptr; // We are no longer pointer at whatever friend we had previously, so he'll get cleaned up next GC cycle.
MyFriendHistory.Empty(); // Drop all our history references too, so those objects will now be cleaned up.
}
You’re likely seeing your array continually grow because whatever you are passing in as “OutSoundWaves” is likely holding on to all the references.
Visual Studio comes with a diagnostic tool which shows your CPU and memory usage over the course of your application lifetime. It’s probably not a very well known feature, but visual studio has a memory profiler tool which is VERY powerful. I have used it to find memory leaks successfully when I have had no idea where to begin looking. Basically, you can take a snapshot of your memory at any point in time (to set a baseline) and then continue taking memory snapshots. Each memory snapshot can be compared against other snapshots, so if you’re seeing memory being allocated and never being released as expected, then you’ve got memory leaks. I’ve been meaning to create an indepth tutorial on how to use this feature, but for now, I think I can point you to this article:
Thank you, since I posted, I made many changes. I added FMemory to read wav files and learned its usage I got that I have to use “delete” if I use NewObject term or if I use Malloc I have to use Free. I prefered using NewObject and delete. I create it assign it and delete before return true. I did it like:
...
OutSoundWaves.Add(sw); //sw :-> USoundWave object which filled with readed FMemory::memcpy data.
delete] rawFile.GetData();
delete sw;
if (sw)
{
if (sw->IsValidLowLevel())
{
sw->ConditionalBeginDestroy(); //instantly clears UObject out of memory
}
}
sw = NULL;
...
}
}
delete searchDir;
delete fileExt;
searchDir = NULL;
fileExt = NULL;
…
return true;
}
Now when I add my node ReadWrite to BP I get null array from OutsoundWaves which is output pin for files. You told that you should useUPROPERTY to keep them alive. Then, should I put UPROPERTY like:
You can’t use UPROPERTY as a function parameter. It has to be in a header. Again, something has to hold on to these files references somewhere. It can’t be the function.
You should also never call delete on anything allocated with NewObject. Those are managed objects, again, just let them “leak” and UE will clean them up for you.
Alright I got that. I did not use delete, conditionalBeginDestroy() or set null for NewObject. I also clean copied data with “rawFile.Clean();” I do not know if that is correct way to destroy it.
I call GC begining of code with no_flags option. I am not sure if I should call at end.
Code works for now. If you think I am missing something let me know please and Thank you.