@@ -1919,7 +1919,16 @@ uint8_t* gc_heap::pad_for_alignment_large (uint8_t* newAlloc, int requiredAlignm
1919
1919
#endif //BACKGROUND_GC && !USE_REGIONS
1920
1920
1921
1921
// This is always power of 2.
1922
+ #ifdef HOST_64BIT
1922
1923
const size_t min_segment_size_hard_limit = 1024*1024*16;
1924
+ #else //HOST_64BIT
1925
+ const size_t min_segment_size_hard_limit = 1024*1024*4;
1926
+ #endif //HOST_64BIT
1927
+
1928
+ #ifndef HOST_64BIT
1929
+ // Max size of heap hard limit (2^31) to be able to be aligned and rounded up on power of 2 and not overflow
1930
+ const size_t max_heap_hard_limit = (size_t)2 * (size_t)1024 * (size_t)1024 * (size_t)1024;
1931
+ #endif //!HOST_64BIT
1923
1932
1924
1933
inline
1925
1934
size_t align_on_segment_hard_limit (size_t add)
@@ -7278,10 +7287,6 @@ bool gc_heap::virtual_commit (void* address, size_t size, int bucket, int h_numb
7278
7287
*
7279
7288
* Note : We never commit into free directly, so bucket != recorded_committed_free_bucket
7280
7289
*/
7281
- #ifndef HOST_64BIT
7282
- assert (heap_hard_limit == 0);
7283
- #endif //!HOST_64BIT
7284
-
7285
7290
assert(0 <= bucket && bucket < recorded_committed_bucket_counts);
7286
7291
assert(bucket < total_oh_count || h_number == -1);
7287
7292
assert(bucket != recorded_committed_free_bucket);
@@ -7385,10 +7390,6 @@ bool gc_heap::virtual_decommit (void* address, size_t size, int bucket, int h_nu
7385
7390
* Case 2: This is for bookkeeping - the bucket will be recorded_committed_bookkeeping_bucket, and the h_number will be -1
7386
7391
* Case 3: This is for free - the bucket will be recorded_committed_free_bucket, and the h_number will be -1
7387
7392
*/
7388
- #ifndef HOST_64BIT
7389
- assert (heap_hard_limit == 0);
7390
- #endif //!HOST_64BIT
7391
-
7392
7393
assert(0 <= bucket && bucket < recorded_committed_bucket_counts);
7393
7394
assert(bucket < total_oh_count || h_number == -1);
7394
7395
@@ -14167,6 +14168,11 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
14167
14168
return E_OUTOFMEMORY;
14168
14169
if (use_large_pages_p)
14169
14170
{
14171
+ #ifndef HOST_64BIT
14172
+ // Large pages are not supported on 32bit
14173
+ assert (false);
14174
+ #endif //!HOST_64BIT
14175
+
14170
14176
if (heap_hard_limit_oh[soh])
14171
14177
{
14172
14178
heap_hard_limit_oh[soh] = soh_segment_size * number_of_heaps;
@@ -20774,12 +20780,12 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
20774
20780
gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_before_oom);
20775
20781
full_compact_gc_p = true;
20776
20782
}
20777
- else if ((current_total_committed * 10) >= (heap_hard_limit * 9))
20783
+ else if (((uint64_t) current_total_committed * (uint64_t) 10) >= ((uint64_t) heap_hard_limit * (uint64_t) 9))
20778
20784
{
20779
20785
size_t loh_frag = get_total_gen_fragmentation (loh_generation);
20780
20786
20781
20787
// If the LOH frag is >= 1/8 it's worth compacting it
20782
- if (( loh_frag * 8) >= heap_hard_limit)
20788
+ if (loh_frag >= heap_hard_limit / 8 )
20783
20789
{
20784
20790
dprintf (GTC_LOG, ("loh frag: %zd > 1/8 of limit %zd", loh_frag, (heap_hard_limit / 8)));
20785
20791
gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_frag);
@@ -20790,7 +20796,7 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
20790
20796
// If there's not much fragmentation but it looks like it'll be productive to
20791
20797
// collect LOH, do that.
20792
20798
size_t est_loh_reclaim = get_total_gen_estimated_reclaim (loh_generation);
20793
- if (( est_loh_reclaim * 8) >= heap_hard_limit)
20799
+ if (est_loh_reclaim >= heap_hard_limit / 8 )
20794
20800
{
20795
20801
gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_reclaim);
20796
20802
full_compact_gc_p = true;
@@ -24369,7 +24375,7 @@ heap_segment* gc_heap::unlink_first_rw_region (int gen_idx)
24369
24375
assert (!heap_segment_read_only_p (region));
24370
24376
dprintf (REGIONS_LOG, ("unlink_first_rw_region on heap: %d gen: %d region: %p", heap_number, gen_idx, heap_segment_mem (region)));
24371
24377
24372
- #if defined(_DEBUG) && defined(HOST_64BIT)
24378
+ #if defined(_DEBUG)
24373
24379
#ifndef COMMITTED_BYTES_SHADOW
24374
24380
if (heap_hard_limit)
24375
24381
#endif //!COMMITTED_BYTES_SHADOW
@@ -24384,7 +24390,7 @@ heap_segment* gc_heap::unlink_first_rw_region (int gen_idx)
24384
24390
g_heaps[old_heap]->committed_by_oh_per_heap[old_oh] -= committed;
24385
24391
check_commit_cs.Leave();
24386
24392
}
24387
- #endif // _DEBUG && HOST_64BIT
24393
+ #endif // _DEBUG
24388
24394
24389
24395
set_heap_for_contained_basic_regions (region, nullptr);
24390
24396
@@ -24412,7 +24418,7 @@ void gc_heap::thread_rw_region_front (int gen_idx, heap_segment* region)
24412
24418
}
24413
24419
dprintf (REGIONS_LOG, ("thread_rw_region_front on heap: %d gen: %d region: %p", heap_number, gen_idx, heap_segment_mem (region)));
24414
24420
24415
- #if defined(_DEBUG) && defined(HOST_64BIT)
24421
+ #if defined(_DEBUG)
24416
24422
#ifndef COMMITTED_BYTES_SHADOW
24417
24423
if (heap_hard_limit)
24418
24424
#endif //!COMMITTED_BYTES_SHADOW
@@ -24427,7 +24433,7 @@ void gc_heap::thread_rw_region_front (int gen_idx, heap_segment* region)
24427
24433
g_heaps[new_heap]->committed_by_oh_per_heap[new_oh] += committed;
24428
24434
check_commit_cs.Leave();
24429
24435
}
24430
- #endif // _DEBUG && HOST_64BIT
24436
+ #endif // _DEBUG
24431
24437
24432
24438
set_heap_for_contained_basic_regions (region, this);
24433
24439
}
@@ -43369,6 +43375,13 @@ void gc_heap::init_static_data()
43369
43375
);
43370
43376
#endif //MULTIPLE_HEAPS
43371
43377
43378
+ if (heap_hard_limit)
43379
+ {
43380
+ size_t gen1_max_size_seg = soh_segment_size / 2;
43381
+ dprintf (GTC_LOG, ("limit gen1 max %zd->%zd", gen1_max_size, gen1_max_size_seg));
43382
+ gen1_max_size = min (gen1_max_size, gen1_max_size_seg);
43383
+ }
43384
+
43372
43385
size_t gen1_max_size_config = (size_t)GCConfig::GetGCGen1MaxBudget();
43373
43386
43374
43387
if (gen1_max_size_config)
@@ -48480,6 +48493,11 @@ HRESULT GCHeap::Initialize()
48480
48493
{
48481
48494
if (gc_heap::heap_hard_limit)
48482
48495
{
48496
+ #ifndef HOST_64BIT
48497
+ // Regions are not supported on 32bit
48498
+ assert(false);
48499
+ #endif //!HOST_64BIT
48500
+
48483
48501
if (gc_heap::heap_hard_limit_oh[soh])
48484
48502
{
48485
48503
gc_heap::regions_range = gc_heap::heap_hard_limit;
@@ -48514,12 +48532,32 @@ HRESULT GCHeap::Initialize()
48514
48532
{
48515
48533
if (gc_heap::heap_hard_limit_oh[soh])
48516
48534
{
48535
+ // On 32bit we have next guarantees:
48536
+ // 0 <= seg_size_from_config <= 1Gb (from max_heap_hard_limit/2)
48537
+ // 0 <= (heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh]) < 4Gb (from gc_heap::compute_hard_limit_from_heap_limits)
48538
+ // 0 <= heap_hard_limit_oh[loh] <= 1Gb or < 2Gb
48539
+ // 0 <= heap_hard_limit_oh[poh] <= 1Gb or < 2Gb
48540
+ // 0 <= large_seg_size <= 1Gb or <= 2Gb (alignment and round up)
48541
+ // 0 <= pin_seg_size <= 1Gb or <= 2Gb (alignment and round up)
48542
+ // 0 <= soh_segment_size + large_seg_size + pin_seg_size <= 4Gb
48543
+ // 4Gb overflow is ok, because 0 size allocation will fail
48517
48544
large_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[loh], nhp), seg_size_from_config);
48518
48545
pin_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[poh], nhp), seg_size_from_config);
48519
48546
}
48520
48547
else
48521
48548
{
48549
+ // On 32bit we have next guarantees:
48550
+ // 0 <= heap_hard_limit <= 1Gb (from gc_heap::compute_hard_limit)
48551
+ // 0 <= soh_segment_size <= 1Gb
48552
+ // 0 <= large_seg_size <= 1Gb
48553
+ // 0 <= pin_seg_size <= 1Gb
48554
+ // 0 <= soh_segment_size + large_seg_size + pin_seg_size <= 3Gb
48555
+ #ifdef HOST_64BIT
48522
48556
large_seg_size = gc_heap::use_large_pages_p ? gc_heap::soh_segment_size : gc_heap::soh_segment_size * 2;
48557
+ #else //HOST_64BIT
48558
+ assert (!gc_heap::use_large_pages_p);
48559
+ large_seg_size = gc_heap::soh_segment_size;
48560
+ #endif //HOST_64BIT
48523
48561
pin_seg_size = large_seg_size;
48524
48562
}
48525
48563
if (gc_heap::use_large_pages_p)
@@ -52683,16 +52721,45 @@ int GCHeap::RefreshMemoryLimit()
52683
52721
return gc_heap::refresh_memory_limit();
52684
52722
}
52685
52723
52724
+ bool gc_heap::compute_hard_limit_from_heap_limits()
52725
+ {
52726
+ #ifndef HOST_64BIT
52727
+ // need to consider overflows:
52728
+ if (! ((heap_hard_limit_oh[soh] < max_heap_hard_limit && heap_hard_limit_oh[loh] <= max_heap_hard_limit / 2 && heap_hard_limit_oh[poh] <= max_heap_hard_limit / 2)
52729
+ || (heap_hard_limit_oh[soh] <= max_heap_hard_limit / 2 && heap_hard_limit_oh[loh] < max_heap_hard_limit && heap_hard_limit_oh[poh] <= max_heap_hard_limit / 2)
52730
+ || (heap_hard_limit_oh[soh] <= max_heap_hard_limit / 2 && heap_hard_limit_oh[loh] <= max_heap_hard_limit / 2 && heap_hard_limit_oh[poh] < max_heap_hard_limit)))
52731
+ {
52732
+ return false;
52733
+ }
52734
+ #endif //!HOST_64BIT
52735
+
52736
+ heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
52737
+ return true;
52738
+ }
52739
+
52740
+ // On 32bit we have next guarantees for limits:
52741
+ // 1) heap-specific limits:
52742
+ // 0 <= (heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh]) < 4Gb
52743
+ // a) 0 <= heap_hard_limit_oh[soh] < 2Gb, 0 <= heap_hard_limit_oh[loh] <= 1Gb, 0 <= heap_hard_limit_oh[poh] <= 1Gb
52744
+ // b) 0 <= heap_hard_limit_oh[soh] <= 1Gb, 0 <= heap_hard_limit_oh[loh] < 2Gb, 0 <= heap_hard_limit_oh[poh] <= 1Gb
52745
+ // c) 0 <= heap_hard_limit_oh[soh] <= 1Gb, 0 <= heap_hard_limit_oh[loh] <= 1Gb, 0 <= heap_hard_limit_oh[poh] < 2Gb
52746
+ // 2) same limit for all heaps:
52747
+ // 0 <= heap_hard_limit <= 1Gb
52748
+ //
52749
+ // These ranges guarantee that calculation of soh_segment_size, loh_segment_size and poh_segment_size with alignment and round up won't overflow,
52750
+ // as well as calculation of sum of them (overflow to 0 is allowed, because allocation with 0 size will fail later).
52686
52751
bool gc_heap::compute_hard_limit()
52687
52752
{
52688
52753
heap_hard_limit_oh[soh] = 0;
52689
- #ifdef HOST_64BIT
52754
+
52690
52755
heap_hard_limit = (size_t)GCConfig::GetGCHeapHardLimit();
52691
52756
heap_hard_limit_oh[soh] = (size_t)GCConfig::GetGCHeapHardLimitSOH();
52692
52757
heap_hard_limit_oh[loh] = (size_t)GCConfig::GetGCHeapHardLimitLOH();
52693
52758
heap_hard_limit_oh[poh] = (size_t)GCConfig::GetGCHeapHardLimitPOH();
52694
52759
52760
+ #ifdef HOST_64BIT
52695
52761
use_large_pages_p = GCConfig::GetGCLargePages();
52762
+ #endif //HOST_64BIT
52696
52763
52697
52764
if (heap_hard_limit_oh[soh] || heap_hard_limit_oh[loh] || heap_hard_limit_oh[poh])
52698
52765
{
@@ -52704,8 +52771,10 @@ bool gc_heap::compute_hard_limit()
52704
52771
{
52705
52772
return false;
52706
52773
}
52707
- heap_hard_limit = heap_hard_limit_oh[soh] +
52708
- heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
52774
+ if (!compute_hard_limit_from_heap_limits())
52775
+ {
52776
+ return false;
52777
+ }
52709
52778
}
52710
52779
else
52711
52780
{
@@ -52733,9 +52802,22 @@ bool gc_heap::compute_hard_limit()
52733
52802
heap_hard_limit_oh[soh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_soh / (uint64_t)100);
52734
52803
heap_hard_limit_oh[loh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_loh / (uint64_t)100);
52735
52804
heap_hard_limit_oh[poh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_poh / (uint64_t)100);
52736
- heap_hard_limit = heap_hard_limit_oh[soh] +
52737
- heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
52805
+
52806
+ if (!compute_hard_limit_from_heap_limits())
52807
+ {
52808
+ return false;
52809
+ }
52810
+ }
52811
+ #ifndef HOST_64BIT
52812
+ else
52813
+ {
52814
+ // need to consider overflows
52815
+ if (heap_hard_limit > max_heap_hard_limit / 2)
52816
+ {
52817
+ return false;
52818
+ }
52738
52819
}
52820
+ #endif //!HOST_64BIT
52739
52821
}
52740
52822
52741
52823
if (heap_hard_limit_oh[soh] && (!heap_hard_limit_oh[poh]) && (!use_large_pages_p))
@@ -52749,9 +52831,17 @@ bool gc_heap::compute_hard_limit()
52749
52831
if ((percent_of_mem > 0) && (percent_of_mem < 100))
52750
52832
{
52751
52833
heap_hard_limit = (size_t)(total_physical_mem * (uint64_t)percent_of_mem / (uint64_t)100);
52834
+
52835
+ #ifndef HOST_64BIT
52836
+ // need to consider overflows
52837
+ if (heap_hard_limit > max_heap_hard_limit / 2)
52838
+ {
52839
+ return false;
52840
+ }
52841
+ #endif //!HOST_64BIT
52752
52842
}
52753
52843
}
52754
- #endif //HOST_64BIT
52844
+
52755
52845
return true;
52756
52846
}
52757
52847
@@ -52776,12 +52866,12 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
52776
52866
}
52777
52867
}
52778
52868
}
52869
+ #endif //HOST_64BIT
52779
52870
52780
52871
if (heap_hard_limit && (heap_hard_limit < new_current_total_committed))
52781
52872
{
52782
52873
return false;
52783
52874
}
52784
- #endif //HOST_64BIT
52785
52875
52786
52876
#ifdef USE_REGIONS
52787
52877
{
@@ -52800,9 +52890,24 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
52800
52890
seg_size_from_config = (size_t)GCConfig::GetSegmentSize();
52801
52891
if (seg_size_from_config)
52802
52892
{
52803
- seg_size_from_config = adjust_segment_size_hard_limit_va (seg_size_from_config);
52893
+ seg_size_from_config = use_large_pages_p ? align_on_segment_hard_limit (seg_size_from_config) :
52894
+ #ifdef HOST_64BIT
52895
+ round_up_power2 (seg_size_from_config);
52896
+ #else //HOST_64BIT
52897
+ round_down_power2 (seg_size_from_config);
52898
+ seg_size_from_config = min (seg_size_from_config, max_heap_hard_limit / 2);
52899
+ #endif //HOST_64BIT
52804
52900
}
52805
52901
52902
+ // On 32bit we have next guarantees:
52903
+ // 0 <= seg_size_from_config <= 1Gb (from max_heap_hard_limit/2)
52904
+ // a) heap-specific limits:
52905
+ // 0 <= (heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh]) < 4Gb (from gc_heap::compute_hard_limit_from_heap_limits)
52906
+ // 0 <= heap_hard_limit_oh[soh] <= 1Gb or < 2Gb
52907
+ // 0 <= soh_segment_size <= 1Gb or <= 2Gb (alignment and round up)
52908
+ // b) same limit for all heaps:
52909
+ // 0 <= heap_hard_limit <= 1Gb
52910
+ // 0 <= soh_segment_size <= 1Gb
52806
52911
size_t limit_to_check = (heap_hard_limit_oh[soh] ? heap_hard_limit_oh[soh] : heap_hard_limit);
52807
52912
soh_segment_size = max (adjust_segment_size_hard_limit (limit_to_check, nhp), seg_size_from_config);
52808
52913
}
0 commit comments