@@ -1925,7 +1925,16 @@ uint8_t* gc_heap::pad_for_alignment_large (uint8_t* newAlloc, int requiredAlignm
19251925#endif //BACKGROUND_GC && !USE_REGIONS
19261926
19271927// This is always power of 2.
1928+ #ifdef HOST_64BIT
19281929const size_t min_segment_size_hard_limit = 1024*1024*16;
1930+ #else //HOST_64BIT
1931+ const size_t min_segment_size_hard_limit = 1024*1024*4;
1932+ #endif //HOST_64BIT
1933+
1934+ #ifndef HOST_64BIT
1935+ // Max size of heap hard limit (2^31) to be able to be aligned and rounded up on power of 2 and not overflow
1936+ const size_t max_heap_hard_limit = (size_t)2 * (size_t)1024 * (size_t)1024 * (size_t)1024;
1937+ #endif //!HOST_64BIT
19291938
19301939inline
19311940size_t align_on_segment_hard_limit (size_t add)
@@ -7299,9 +7308,6 @@ bool gc_heap::virtual_commit (void* address, size_t size, int bucket, int h_numb
72997308 *
73007309 * Note : We never commit into free directly, so bucket != recorded_committed_free_bucket
73017310 */
7302- #ifndef HOST_64BIT
7303- assert (heap_hard_limit == 0);
7304- #endif //!HOST_64BIT
73057311
73067312 assert(0 <= bucket && bucket < recorded_committed_bucket_counts);
73077313 assert(bucket < total_oh_count || h_number == -1);
@@ -7444,9 +7450,6 @@ bool gc_heap::virtual_decommit (void* address, size_t size, int bucket, int h_nu
74447450 * Case 2: This is for bookkeeping - the bucket will be recorded_committed_bookkeeping_bucket, and the h_number will be -1
74457451 * Case 3: This is for free - the bucket will be recorded_committed_free_bucket, and the h_number will be -1
74467452 */
7447- #ifndef HOST_64BIT
7448- assert (heap_hard_limit == 0);
7449- #endif //!HOST_64BIT
74507453
74517454 bool decommit_succeeded_p = ((bucket != recorded_committed_bookkeeping_bucket) && use_large_pages_p) ? true : GCToOSInterface::VirtualDecommit (address, size);
74527455
@@ -14202,6 +14205,11 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
1420214205 return E_OUTOFMEMORY;
1420314206 if (use_large_pages_p)
1420414207 {
14208+ #ifndef HOST_64BIT
14209+ // Large pages are not supported on 32bit
14210+ assert (false);
14211+ #endif //!HOST_64BIT
14212+
1420514213 if (heap_hard_limit_oh[soh])
1420614214 {
1420714215 heap_hard_limit_oh[soh] = soh_segment_size * number_of_heaps;
@@ -20815,12 +20823,12 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
2081520823 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_before_oom);
2081620824 full_compact_gc_p = true;
2081720825 }
20818- else if ((current_total_committed * 10) >= (heap_hard_limit * 9))
20826+ else if (((uint64_t) current_total_committed * (uint64_t) 10) >= ((uint64_t) heap_hard_limit * (uint64_t) 9))
2081920827 {
2082020828 size_t loh_frag = get_total_gen_fragmentation (loh_generation);
2082120829
2082220830 // If the LOH frag is >= 1/8 it's worth compacting it
20823- if (( loh_frag * 8) >= heap_hard_limit)
20831+ if (loh_frag >= heap_hard_limit / 8 )
2082420832 {
2082520833 dprintf (GTC_LOG, ("loh frag: %zd > 1/8 of limit %zd", loh_frag, (heap_hard_limit / 8)));
2082620834 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_frag);
@@ -20831,7 +20839,7 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
2083120839 // If there's not much fragmentation but it looks like it'll be productive to
2083220840 // collect LOH, do that.
2083320841 size_t est_loh_reclaim = get_total_gen_estimated_reclaim (loh_generation);
20834- if (( est_loh_reclaim * 8) >= heap_hard_limit)
20842+ if (est_loh_reclaim >= heap_hard_limit / 8 )
2083520843 {
2083620844 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_reclaim);
2083720845 full_compact_gc_p = true;
@@ -43235,6 +43243,15 @@ void gc_heap::init_static_data()
4323543243 );
4323643244#endif //MULTIPLE_HEAPS
4323743245
43246+ #ifndef HOST_64BIT
43247+ if (heap_hard_limit)
43248+ {
43249+ size_t gen1_max_size_seg = soh_segment_size / 2;
43250+ dprintf (GTC_LOG, ("limit gen1 max %zd->%zd", gen1_max_size, gen1_max_size_seg));
43251+ gen1_max_size = min (gen1_max_size, gen1_max_size_seg);
43252+ }
43253+ #endif //!HOST_64BIT
43254+
4323843255 size_t gen1_max_size_config = (size_t)GCConfig::GetGCGen1MaxBudget();
4323943256
4324043257 if (gen1_max_size_config)
@@ -48333,6 +48350,11 @@ HRESULT GCHeap::Initialize()
4833348350 {
4833448351 if (gc_heap::heap_hard_limit)
4833548352 {
48353+ #ifndef HOST_64BIT
48354+ // Regions are not supported on 32bit
48355+ assert(false);
48356+ #endif //!HOST_64BIT
48357+
4833648358 if (gc_heap::heap_hard_limit_oh[soh])
4833748359 {
4833848360 gc_heap::regions_range = gc_heap::heap_hard_limit;
@@ -48367,12 +48389,32 @@ HRESULT GCHeap::Initialize()
4836748389 {
4836848390 if (gc_heap::heap_hard_limit_oh[soh])
4836948391 {
48392+ // On 32bit we have next guarantees:
48393+ // 0 <= seg_size_from_config <= 1Gb (from max_heap_hard_limit/2)
48394+ // 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)
48395+ // 0 <= heap_hard_limit_oh[loh] <= 1Gb or < 2Gb
48396+ // 0 <= heap_hard_limit_oh[poh] <= 1Gb or < 2Gb
48397+ // 0 <= large_seg_size <= 1Gb or <= 2Gb (alignment and round up)
48398+ // 0 <= pin_seg_size <= 1Gb or <= 2Gb (alignment and round up)
48399+ // 0 <= soh_segment_size + large_seg_size + pin_seg_size <= 4Gb
48400+ // 4Gb overflow is ok, because 0 size allocation will fail
4837048401 large_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[loh], nhp), seg_size_from_config);
4837148402 pin_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[poh], nhp), seg_size_from_config);
4837248403 }
4837348404 else
4837448405 {
48406+ // On 32bit we have next guarantees:
48407+ // 0 <= heap_hard_limit <= 1Gb (from gc_heap::compute_hard_limit)
48408+ // 0 <= soh_segment_size <= 1Gb
48409+ // 0 <= large_seg_size <= 1Gb
48410+ // 0 <= pin_seg_size <= 1Gb
48411+ // 0 <= soh_segment_size + large_seg_size + pin_seg_size <= 3Gb
48412+ #ifdef HOST_64BIT
4837548413 large_seg_size = gc_heap::use_large_pages_p ? gc_heap::soh_segment_size : gc_heap::soh_segment_size * 2;
48414+ #else //HOST_64BIT
48415+ assert (!gc_heap::use_large_pages_p);
48416+ large_seg_size = gc_heap::soh_segment_size;
48417+ #endif //HOST_64BIT
4837648418 pin_seg_size = large_seg_size;
4837748419 }
4837848420 if (gc_heap::use_large_pages_p)
@@ -52613,16 +52655,45 @@ int GCHeap::RefreshMemoryLimit()
5261352655 return gc_heap::refresh_memory_limit();
5261452656}
5261552657
52658+ bool gc_heap::compute_hard_limit_from_heap_limits()
52659+ {
52660+ #ifndef HOST_64BIT
52661+ // need to consider overflows:
52662+ 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)
52663+ || (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)
52664+ || (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)))
52665+ {
52666+ return false;
52667+ }
52668+ #endif //!HOST_64BIT
52669+
52670+ heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
52671+ return true;
52672+ }
52673+
52674+ // On 32bit we have next guarantees for limits:
52675+ // 1) heap-specific limits:
52676+ // 0 <= (heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh]) < 4Gb
52677+ // a) 0 <= heap_hard_limit_oh[soh] < 2Gb, 0 <= heap_hard_limit_oh[loh] <= 1Gb, 0 <= heap_hard_limit_oh[poh] <= 1Gb
52678+ // b) 0 <= heap_hard_limit_oh[soh] <= 1Gb, 0 <= heap_hard_limit_oh[loh] < 2Gb, 0 <= heap_hard_limit_oh[poh] <= 1Gb
52679+ // c) 0 <= heap_hard_limit_oh[soh] <= 1Gb, 0 <= heap_hard_limit_oh[loh] <= 1Gb, 0 <= heap_hard_limit_oh[poh] < 2Gb
52680+ // 2) same limit for all heaps:
52681+ // 0 <= heap_hard_limit <= 1Gb
52682+ //
52683+ // These ranges guarantee that calculation of soh_segment_size, loh_segment_size and poh_segment_size with alignment and round up won't overflow,
52684+ // as well as calculation of sum of them (overflow to 0 is allowed, because allocation with 0 size will fail later).
5261652685bool gc_heap::compute_hard_limit()
5261752686{
5261852687 heap_hard_limit_oh[soh] = 0;
52619- #ifdef HOST_64BIT
52688+
5262052689 heap_hard_limit = (size_t)GCConfig::GetGCHeapHardLimit();
5262152690 heap_hard_limit_oh[soh] = (size_t)GCConfig::GetGCHeapHardLimitSOH();
5262252691 heap_hard_limit_oh[loh] = (size_t)GCConfig::GetGCHeapHardLimitLOH();
5262352692 heap_hard_limit_oh[poh] = (size_t)GCConfig::GetGCHeapHardLimitPOH();
5262452693
52694+ #ifdef HOST_64BIT
5262552695 use_large_pages_p = GCConfig::GetGCLargePages();
52696+ #endif //HOST_64BIT
5262652697
5262752698 if (heap_hard_limit_oh[soh] || heap_hard_limit_oh[loh] || heap_hard_limit_oh[poh])
5262852699 {
@@ -52634,8 +52705,10 @@ bool gc_heap::compute_hard_limit()
5263452705 {
5263552706 return false;
5263652707 }
52637- heap_hard_limit = heap_hard_limit_oh[soh] +
52638- heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
52708+ if (!compute_hard_limit_from_heap_limits())
52709+ {
52710+ return false;
52711+ }
5263952712 }
5264052713 else
5264152714 {
@@ -52663,9 +52736,22 @@ bool gc_heap::compute_hard_limit()
5266352736 heap_hard_limit_oh[soh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_soh / (uint64_t)100);
5266452737 heap_hard_limit_oh[loh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_loh / (uint64_t)100);
5266552738 heap_hard_limit_oh[poh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_poh / (uint64_t)100);
52666- heap_hard_limit = heap_hard_limit_oh[soh] +
52667- heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
52739+
52740+ if (!compute_hard_limit_from_heap_limits())
52741+ {
52742+ return false;
52743+ }
5266852744 }
52745+ #ifndef HOST_64BIT
52746+ else
52747+ {
52748+ // need to consider overflows
52749+ if (heap_hard_limit > max_heap_hard_limit / 2)
52750+ {
52751+ return false;
52752+ }
52753+ }
52754+ #endif //!HOST_64BIT
5266952755 }
5267052756
5267152757 if (heap_hard_limit_oh[soh] && (!heap_hard_limit_oh[poh]) && (!use_large_pages_p))
@@ -52679,9 +52765,17 @@ bool gc_heap::compute_hard_limit()
5267952765 if ((percent_of_mem > 0) && (percent_of_mem < 100))
5268052766 {
5268152767 heap_hard_limit = (size_t)(total_physical_mem * (uint64_t)percent_of_mem / (uint64_t)100);
52768+
52769+ #ifndef HOST_64BIT
52770+ // need to consider overflows
52771+ if (heap_hard_limit > max_heap_hard_limit / 2)
52772+ {
52773+ return false;
52774+ }
52775+ #endif //!HOST_64BIT
5268252776 }
5268352777 }
52684- #endif //HOST_64BIT
52778+
5268552779 return true;
5268652780}
5268752781
@@ -52706,12 +52800,12 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
5270652800 }
5270752801 }
5270852802 }
52803+ #endif //HOST_64BIT
5270952804
5271052805 if (heap_hard_limit && (heap_hard_limit < new_current_total_committed))
5271152806 {
5271252807 return false;
5271352808 }
52714- #endif //HOST_64BIT
5271552809
5271652810#ifdef USE_REGIONS
5271752811 {
@@ -52730,9 +52824,24 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
5273052824 seg_size_from_config = (size_t)GCConfig::GetSegmentSize();
5273152825 if (seg_size_from_config)
5273252826 {
52733- seg_size_from_config = adjust_segment_size_hard_limit_va (seg_size_from_config);
52827+ seg_size_from_config = use_large_pages_p ? align_on_segment_hard_limit (seg_size_from_config) :
52828+ #ifdef HOST_64BIT
52829+ round_up_power2 (seg_size_from_config);
52830+ #else //HOST_64BIT
52831+ round_down_power2 (seg_size_from_config);
52832+ seg_size_from_config = min (seg_size_from_config, max_heap_hard_limit / 2);
52833+ #endif //HOST_64BIT
5273452834 }
5273552835
52836+ // On 32bit we have next guarantees:
52837+ // 0 <= seg_size_from_config <= 1Gb (from max_heap_hard_limit/2)
52838+ // a) heap-specific limits:
52839+ // 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)
52840+ // 0 <= heap_hard_limit_oh[soh] <= 1Gb or < 2Gb
52841+ // 0 <= soh_segment_size <= 1Gb or <= 2Gb (alignment and round up)
52842+ // b) same limit for all heaps:
52843+ // 0 <= heap_hard_limit <= 1Gb
52844+ // 0 <= soh_segment_size <= 1Gb
5273652845 size_t limit_to_check = (heap_hard_limit_oh[soh] ? heap_hard_limit_oh[soh] : heap_hard_limit);
5273752846 soh_segment_size = max (adjust_segment_size_hard_limit (limit_to_check, nhp), seg_size_from_config);
5273852847 }
0 commit comments