Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Double the size of new frozen segments #76870

Merged
merged 2 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions src/coreclr/vm/frozenobjectheap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#include "common.h"
#include "frozenobjectheap.h"

// Size to reserve for a frozen segment
#define FOH_SEGMENT_SIZE (4 * 1024 * 1024)
// Default size to reserve for a frozen segment
#define FOH_SEGMENT_DEFAULT_SIZE (4 * 1024 * 1024)
// Size to commit on demand in that reserved space
#define FOH_COMMIT_SIZE (64 * 1024)

Expand Down Expand Up @@ -36,8 +36,6 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t

_ASSERT(type != nullptr);
_ASSERT(FOH_COMMIT_SIZE >= MIN_OBJECT_SIZE);
_ASSERT(FOH_SEGMENT_SIZE > FOH_COMMIT_SIZE);
_ASSERT(FOH_SEGMENT_SIZE % FOH_COMMIT_SIZE == 0);

// NOTE: objectSize is expected be the full size including header
_ASSERT(objectSize >= MIN_OBJECT_SIZE);
Expand All @@ -52,7 +50,7 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t
if (m_CurrentSegment == nullptr)
{
// Create the first segment on first allocation
m_CurrentSegment = new FrozenObjectSegment();
m_CurrentSegment = new FrozenObjectSegment(FOH_SEGMENT_DEFAULT_SIZE);
m_FrozenSegments.Append(m_CurrentSegment);
_ASSERT(m_CurrentSegment != nullptr);
}
Expand All @@ -63,7 +61,10 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t
// to create a new one
if (obj == nullptr)
{
m_CurrentSegment = new FrozenObjectSegment();
// Double the reserved size to reduce the number of frozen segments in apps with lots of frozen objects
// Use the same size in case if prevSegmentSize*2 operation overflows.
size_t prevSegmentSize = m_CurrentSegment->GetSize();
m_CurrentSegment = new FrozenObjectSegment(max(prevSegmentSize, prevSegmentSize * 2));
m_FrozenSegments.Append(m_CurrentSegment);

// Try again
Expand All @@ -76,18 +77,35 @@ Object* FrozenObjectHeapManager::TryAllocateObject(PTR_MethodTable type, size_t
#endif // !FEATURE_BASICFREEZE
}


FrozenObjectSegment::FrozenObjectSegment():
// Reserve sizeHint bytes of memory for the given frozen segment.
// The requested size can be be ignored in case of memory pressure and FOH_SEGMENT_DEFAULT_SIZE is used instead.
FrozenObjectSegment::FrozenObjectSegment(size_t sizeHint) :
m_pStart(nullptr),
m_pCurrent(nullptr),
m_SizeCommitted(0),
m_Size(sizeHint),
m_SegmentHandle(nullptr)
COMMA_INDEBUG(m_ObjectsCount(0))
{
void* alloc = ClrVirtualAlloc(nullptr, FOH_SEGMENT_SIZE, MEM_RESERVE, PAGE_READWRITE);
_ASSERT(m_Size > FOH_COMMIT_SIZE);
_ASSERT(m_Size % FOH_COMMIT_SIZE == 0);

void* alloc = ClrVirtualAlloc(nullptr, m_Size, MEM_RESERVE, PAGE_READWRITE);
if (alloc == nullptr)
{
ThrowOutOfMemory();
// Try again with the default FOH size
if (m_Size > FOH_SEGMENT_DEFAULT_SIZE)
{
m_Size = FOH_SEGMENT_DEFAULT_SIZE;
_ASSERT(m_Size > FOH_COMMIT_SIZE);
_ASSERT(m_Size % FOH_COMMIT_SIZE == 0);
alloc = ClrVirtualAlloc(nullptr, m_Size, MEM_RESERVE, PAGE_READWRITE);
}

if (alloc == nullptr)
{
ThrowOutOfMemory();
}
}

// Commit a chunk in advance
Expand All @@ -107,7 +125,7 @@ FrozenObjectSegment::FrozenObjectSegment():
si.ibFirstObject = sizeof(ObjHeader);
si.ibAllocated = si.ibFirstObject;
si.ibCommit = FOH_COMMIT_SIZE;
si.ibReserved = FOH_SEGMENT_SIZE;
si.ibReserved = m_Size;

m_SegmentHandle = GCHeapUtilities::GetGCHeap()->RegisterFrozenSegment(&si);
if (m_SegmentHandle == nullptr)
Expand All @@ -125,13 +143,13 @@ FrozenObjectSegment::FrozenObjectSegment():

Object* FrozenObjectSegment::TryAllocateObject(PTR_MethodTable type, size_t objectSize)
{
_ASSERT(m_pStart != nullptr && FOH_SEGMENT_SIZE > 0 && m_SegmentHandle != nullptr); // Expected to be inited
_ASSERT(m_pStart != nullptr && m_Size > 0 && m_SegmentHandle != nullptr); // Expected to be inited
_ASSERT(IS_ALIGNED(m_pCurrent, DATA_ALIGNMENT));
_ASSERT(objectSize <= FOH_COMMIT_SIZE);
_ASSERT(m_pCurrent >= m_pStart + sizeof(ObjHeader));

const size_t spaceUsed = (size_t)(m_pCurrent - m_pStart);
const size_t spaceLeft = FOH_SEGMENT_SIZE - spaceUsed;
const size_t spaceLeft = m_Size - spaceUsed;

_ASSERT(spaceUsed >= sizeof(ObjHeader));
_ASSERT(spaceLeft >= sizeof(ObjHeader));
Expand All @@ -146,7 +164,7 @@ Object* FrozenObjectSegment::TryAllocateObject(PTR_MethodTable type, size_t obje
if (spaceUsed + objectSize + sizeof(ObjHeader) > m_SizeCommitted)
{
// Make sure we don't go out of bounds during this commit
_ASSERT(m_SizeCommitted + FOH_COMMIT_SIZE <= FOH_SEGMENT_SIZE);
_ASSERT(m_SizeCommitted + FOH_COMMIT_SIZE <= m_Size);

if (ClrVirtualAlloc(m_pStart + m_SizeCommitted, FOH_COMMIT_SIZE, MEM_COMMIT, PAGE_READWRITE) == nullptr)
{
Expand Down
10 changes: 9 additions & 1 deletion src/coreclr/vm/frozenobjectheap.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,14 @@ class FrozenObjectHeapManager
class FrozenObjectSegment
{
public:
FrozenObjectSegment();
FrozenObjectSegment(size_t sizeHint);
Object* TryAllocateObject(PTR_MethodTable type, size_t objectSize);

size_t GetSize() const
{
return m_Size;
}

private:
// Start of the reserved memory, the first object starts at "m_pStart + sizeof(ObjHeader)" (its pMT)
uint8_t* m_pStart;
Expand All @@ -56,6 +61,9 @@ class FrozenObjectSegment
// m_SizeCommitted <= m_pStart + FOH_SIZE_RESERVED
size_t m_SizeCommitted;

// Total memory reserved for the current segment
size_t m_Size;

segment_handle m_SegmentHandle;
INDEBUG(size_t m_ObjectsCount);
};
Expand Down