diff --git a/src/gpgmm/MemoryAllocator.cpp b/src/gpgmm/MemoryAllocator.cpp index 312eeb22c..5c02c16c5 100644 --- a/src/gpgmm/MemoryAllocator.cpp +++ b/src/gpgmm/MemoryAllocator.cpp @@ -72,6 +72,16 @@ namespace gpgmm { AppendChild(std::move(child)); } + MemoryAllocator::~MemoryAllocator() { + // If memory cannot be reused by a (parent) allocator, ensure no used memory leaked. + if (GetParent() == nullptr) { + ASSERT(mInfo.UsedBlockUsage == 0u); + ASSERT(mInfo.UsedBlockCount == 0u); + ASSERT(mInfo.UsedMemoryCount == 0u); + ASSERT(mInfo.UsedMemoryUsage == 0u); + } + } + std::unique_ptr MemoryAllocator::TryAllocateMemory(uint64_t requestSize, uint64_t alignment, bool neverAllocate, diff --git a/src/gpgmm/MemoryAllocator.h b/src/gpgmm/MemoryAllocator.h index 6a5b351f0..15ff69496 100644 --- a/src/gpgmm/MemoryAllocator.h +++ b/src/gpgmm/MemoryAllocator.h @@ -83,7 +83,7 @@ namespace gpgmm { // Constructs a MemoryAllocator that owns a single child allocator. explicit MemoryAllocator(std::unique_ptr child); - virtual ~MemoryAllocator() override = default; + virtual ~MemoryAllocator() override; // Attempts to allocate memory and return an allocation that has at-least // |requestedSize| allocated space whose value is a multiple of |alignment|. If it cannot, diff --git a/src/gpgmm/PooledMemoryAllocator.cpp b/src/gpgmm/PooledMemoryAllocator.cpp index f61197616..4d8c7b556 100644 --- a/src/gpgmm/PooledMemoryAllocator.cpp +++ b/src/gpgmm/PooledMemoryAllocator.cpp @@ -64,7 +64,10 @@ namespace gpgmm { mInfo.UsedMemoryCount--; mInfo.UsedMemoryUsage -= allocationSize; - mPool->ReturnToPool(std::move(allocation)); + MemoryBase* memory = allocation->GetMemory(); + ASSERT(memory != nullptr); + + mPool->ReturnToPool(std::make_unique(GetFirstChild(), memory)); } uint64_t PooledMemoryAllocator::GetMemorySize() const { diff --git a/src/gpgmm/StandaloneMemoryAllocator.cpp b/src/gpgmm/StandaloneMemoryAllocator.cpp index 15975226d..f43467704 100644 --- a/src/gpgmm/StandaloneMemoryAllocator.cpp +++ b/src/gpgmm/StandaloneMemoryAllocator.cpp @@ -45,15 +45,17 @@ namespace gpgmm { new MemoryBlock{0, requestSize}); } - void StandaloneMemoryAllocator::DeallocateMemory( - std::unique_ptr subAllocation) { + void StandaloneMemoryAllocator::DeallocateMemory(std::unique_ptr allocation) { TRACE_EVENT0(TraceEventCategory::Default, "StandaloneMemoryAllocator.DeallocateMemory"); std::lock_guard lock(mMutex); + + MemoryBlock* block = allocation->GetBlock(); mInfo.UsedBlockCount--; - mInfo.UsedBlockUsage -= subAllocation->GetSize(); - SafeDelete(subAllocation->GetBlock()); - GetFirstChild()->DeallocateMemory(std::move(subAllocation)); + mInfo.UsedBlockUsage -= block->Size; + + SafeDelete(block); + GetFirstChild()->DeallocateMemory(std::move(allocation)); } MEMORY_ALLOCATOR_INFO StandaloneMemoryAllocator::GetInfo() const { diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp index b65e62959..d4308d8bb 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp @@ -846,6 +846,8 @@ namespace gpgmm { namespace d3d12 { HRESULT ResourceAllocator::CreateResource(ComPtr resource, ResourceAllocation** resourceAllocationOut) { + std::lock_guard lock(mMutex); + if (!resourceAllocationOut) { return E_POINTER; } @@ -865,6 +867,10 @@ namespace gpgmm { namespace d3d12 { resource, GetPreferredMemorySegmentGroup(mDevice.Get(), mIsUMA, heapProperties.Type), resourceInfo.SizeInBytes); + mInfo.UsedMemoryUsage += resourceInfo.SizeInBytes; + mInfo.UsedMemoryCount++; + mInfo.UsedBlockUsage += resourceInfo.SizeInBytes; + *resourceAllocationOut = new ResourceAllocation{/*residencyManager*/ nullptr, /*allocator*/ this, /*offsetFromHeap*/ kInvalidOffset, diff --git a/src/tests/unittests/SlabMemoryAllocatorTests.cpp b/src/tests/unittests/SlabMemoryAllocatorTests.cpp index 1eb531424..17fb3feef 100644 --- a/src/tests/unittests/SlabMemoryAllocatorTests.cpp +++ b/src/tests/unittests/SlabMemoryAllocatorTests.cpp @@ -74,6 +74,8 @@ TEST(SlabMemoryAllocatorTests, SingleSlab) { EXPECT_EQ(allocation->GetOffset(), 0u); EXPECT_EQ(allocation->GetMethod(), AllocationMethod::kSubAllocated); EXPECT_GE(allocation->GetSize(), kBlockSize); + + allocator.DeallocateMemory(std::move(allocation)); } // Verify allocation cannot exceed the fragmentation threshold. @@ -97,6 +99,8 @@ TEST(SlabMemoryAllocatorTests, SingleSlab) { EXPECT_EQ(allocation->GetOffset(), 0u); EXPECT_EQ(allocation->GetMethod(), AllocationMethod::kSubAllocated); EXPECT_GE(allocation->GetSize(), kBlockSize); + + allocator.DeallocateMemory(std::move(allocation)); } // Verify allocation succeeds when specifying a slab size. @@ -113,6 +117,8 @@ TEST(SlabMemoryAllocatorTests, SingleSlab) { ASSERT_NE(allocation, nullptr); EXPECT_GE(allocation->GetSize(), kBlockSize); EXPECT_GE(allocation->GetMemory()->GetSize(), kSlabSize); + + allocator.DeallocateMemory(std::move(allocation)); } // Verify allocation succeeds when specifying a NPOT slab size. @@ -129,6 +135,8 @@ TEST(SlabMemoryAllocatorTests, SingleSlab) { ASSERT_NE(allocation, nullptr); EXPECT_GE(allocation->GetSize(), kBlockSize); EXPECT_GE(allocation->GetMemory()->GetSize(), kSlabSize); + + allocator.DeallocateMemory(std::move(allocation)); } // Verify requesting an allocation without memory will not return a valid allocation.