Skip to content

Commit

Permalink
Using AllocateUninitializedArray in array pool (dotnet/coreclr#24504)
Browse files Browse the repository at this point in the history
* Just use `new T[]` when elements are not pointer-free

* reduce zeroing out when not necessary.

* use AllocateUninitializedArray in ArrayPool


Commit migrated from dotnet/coreclr@4ca032d
  • Loading branch information
VSadov committed May 28, 2019
1 parent 72eab53 commit 2379994
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 19 deletions.
5 changes: 5 additions & 0 deletions src/coreclr/src/System.Private.CoreLib/src/System/GC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,11 @@ internal static void UnregisterMemoryLoadChangeNotification(Action notification)
// the array is always zero-initialized.
internal static T[] AllocateUninitializedArray<T>(int length)
{
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
return new T[length];
}

if (length < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, 0, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
#if DEBUG
Expand Down
42 changes: 28 additions & 14 deletions src/coreclr/src/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11517,9 +11517,9 @@ void gc_heap::adjust_limit_clr (uint8_t* start, size_t limit_size, size_t size,
if (gen_number == 0)
{
size_t pad_size = Align (min_obj_size, align_const);
make_unused_array (acontext->alloc_ptr, pad_size);
dprintf (3, ("contigous ac: making min obj gap %Ix->%Ix(%Id)",
acontext->alloc_ptr, (acontext->alloc_ptr + pad_size), pad_size));
make_unused_array (acontext->alloc_ptr, pad_size);
acontext->alloc_ptr += pad_size;
}
}
Expand Down Expand Up @@ -11581,6 +11581,7 @@ void gc_heap::adjust_limit_clr (uint8_t* start, size_t limit_size, size_t size,
*(PTR_PTR)clear_start = 0;
}
// skip the rest of the object
dprintf(3, ("zeroing optional: skipping object at %Ix->%Ix(%Id)", clear_start, obj_end, obj_end - clear_start));
clear_start = obj_end;
}

Expand Down Expand Up @@ -11643,7 +11644,10 @@ void gc_heap::adjust_limit_clr (uint8_t* start, size_t limit_size, size_t size,
}

// verifying the memory is completely cleared.
//verify_mem_cleared (start - plug_skew, limit_size);
//if (!(flags & GC_ALLOC_ZEROING_OPTIONAL))
//{
// verify_mem_cleared(start - plug_skew, limit_size);
//}
}

size_t gc_heap::new_allocation_limit (size_t size, size_t physical_limit, int gen_number)
Expand Down Expand Up @@ -12129,6 +12133,7 @@ void gc_heap::bgc_loh_alloc_clr (uint8_t* alloc_start,
add_saved_spinlock_info (true, me_release, mt_clr_large_mem);
leave_spin_lock (&more_space_lock_loh);

((void**) alloc_start)[-1] = 0; //clear the sync block
if (!(flags & GC_ALLOC_ZEROING_OPTIONAL))
{
memclr(alloc_start + size_to_skip, size_to_clear);
Expand Down Expand Up @@ -12264,8 +12269,8 @@ BOOL gc_heap::a_fit_segment_end_p (int gen_number,
#endif //BACKGROUND_GC

uint8_t*& allocated = ((gen_number == 0) ?
alloc_allocated :
heap_segment_allocated(seg));
alloc_allocated :
heap_segment_allocated(seg));

size_t pad = Align (min_obj_size, align_const);

Expand Down Expand Up @@ -12327,33 +12332,42 @@ BOOL gc_heap::a_fit_segment_end_p (int gen_number,
}
#endif //BACKGROUND_GC

uint8_t* old_alloc;
old_alloc = allocated;
#ifdef FEATURE_LOH_COMPACTION
if (gen_number == (max_generation + 1))
{
make_unused_array (old_alloc, loh_pad);
old_alloc += loh_pad;
make_unused_array (allocated, loh_pad);
allocated += loh_pad;
limit -= loh_pad;
}
#endif //FEATURE_LOH_COMPACTION

#if defined (VERIFY_HEAP) && defined (_DEBUG)
((void**) allocated)[-1] = 0; //clear the sync block
#endif //VERIFY_HEAP && _DEBUG
allocated += limit;

dprintf (3, ("found fit at end of seg: %Ix", old_alloc));

uint8_t* old_alloc;
old_alloc = allocated;

#ifdef BACKGROUND_GC
if (cookie != -1)
{
allocated += limit;
bgc_loh_alloc_clr (old_alloc, limit, acontext, flags, align_const, cookie, TRUE, seg);
}
else
#endif //BACKGROUND_GC
{
{
// In a contiguous AC case with GC_ALLOC_ZEROING_OPTIONAL, deduct unspent space from the limit to clear only what is necessary.
if ((flags & GC_ALLOC_ZEROING_OPTIONAL) &&
((allocated == acontext->alloc_limit) || (allocated == (acontext->alloc_limit + Align (min_obj_size, align_const)))))
{
assert(gen_number == 0);
assert(allocated > acontext->alloc_ptr);

limit -= (allocated - acontext->alloc_ptr);
// add space for an AC continuity divider
limit += Align(min_obj_size, align_const);
}

allocated += limit;
adjust_limit_clr (old_alloc, limit, size, acontext, flags, seg, align_const, gen_number);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ public override T[] Rent(int minimumLength)

// The pool was exhausted for this buffer size. Allocate a new buffer with a size corresponding
// to the appropriate bucket.
buffer = new T[_buckets[index]._bufferLength];
buffer = GC.AllocateUninitializedArray<T>(_buckets[index]._bufferLength);
}
else
{
// The request was for a size too large for the pool. Allocate an array of exactly the requested length.
// When it's returned to the pool, we'll simply throw it away.
buffer = new T[minimumLength];
buffer = GC.AllocateUninitializedArray<T>(minimumLength);
}

if (log.IsEnabled())
Expand Down Expand Up @@ -215,7 +215,7 @@ internal Bucket(int bufferLength, int numberOfBuffers, int poolId)
// for that slot, in which case we should do so now.
if (allocateBuffer)
{
buffer = new T[_bufferLength];
buffer = GC.AllocateUninitializedArray<T>(_bufferLength);

var log = ArrayPoolEventSource.Log;
if (log.IsEnabled())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ public override T[] Rent(int minimumLength)
}

// No buffer available. Allocate a new buffer with a size corresponding to the appropriate bucket.
buffer = new T[_bucketArraySizes[bucketIndex]];
buffer = GC.AllocateUninitializedArray<T>(_bucketArraySizes[bucketIndex]);
}
else
{
// The request was for a size too large for the pool. Allocate an array of exactly the requested length.
// When it's returned to the pool, we'll simply throw it away.
buffer = new T[minimumLength];
buffer = GC.AllocateUninitializedArray<T>(minimumLength);
}

if (log.IsEnabled())
Expand Down

0 comments on commit 2379994

Please sign in to comment.