@@ -1968,7 +1968,16 @@ uint8_t* gc_heap::pad_for_alignment_large (uint8_t* newAlloc, int requiredAlignm
19681968#endif //BACKGROUND_GC && !USE_REGIONS
19691969
19701970// This is always power of 2.
1971+ #ifdef HOST_64BIT
19711972const size_t min_segment_size_hard_limit = 1024*1024*16;
1973+ #else //HOST_64BIT
1974+ const size_t min_segment_size_hard_limit = 1024*1024*4;
1975+ #endif //HOST_64BIT
1976+
1977+ #ifndef HOST_64BIT
1978+ // Max size of heap hard limit (2^31) to be able to be aligned and rounded up on power of 2 and not overflow
1979+ const size_t max_heap_hard_limit = (size_t)2 * (size_t)1024 * (size_t)1024 * (size_t)1024;
1980+ #endif //!HOST_64BIT
19721981
19731982inline
19741983size_t align_on_segment_hard_limit (size_t add)
@@ -7405,9 +7414,6 @@ bool gc_heap::virtual_commit (void* address, size_t size, int bucket, int h_numb
74057414 *
74067415 * Note : We never commit into free directly, so bucket != recorded_committed_free_bucket
74077416 */
7408- #ifndef HOST_64BIT
7409- assert (heap_hard_limit == 0);
7410- #endif //!HOST_64BIT
74117417
74127418 assert(0 <= bucket && bucket < recorded_committed_bucket_counts);
74137419 assert(bucket < total_oh_count || h_number == -1);
@@ -7550,9 +7556,6 @@ bool gc_heap::virtual_decommit (void* address, size_t size, int bucket, int h_nu
75507556 * Case 2: This is for bookkeeping - the bucket will be recorded_committed_bookkeeping_bucket, and the h_number will be -1
75517557 * Case 3: This is for free - the bucket will be recorded_committed_free_bucket, and the h_number will be -1
75527558 */
7553- #ifndef HOST_64BIT
7554- assert (heap_hard_limit == 0);
7555- #endif //!HOST_64BIT
75567559
75577560 bool decommit_succeeded_p = ((bucket != recorded_committed_bookkeeping_bucket) && use_large_pages_p) ? true : GCToOSInterface::VirtualDecommit (address, size);
75587561
@@ -14347,6 +14350,11 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
1434714350 return E_OUTOFMEMORY;
1434814351 if (use_large_pages_p)
1434914352 {
14353+ #ifndef HOST_64BIT
14354+ // Large pages are not supported on 32bit
14355+ assert (false);
14356+ #endif //!HOST_64BIT
14357+
1435014358 if (heap_hard_limit_oh[soh])
1435114359 {
1435214360 heap_hard_limit_oh[soh] = soh_segment_size * number_of_heaps;
@@ -20975,12 +20983,12 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
2097520983 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_before_oom);
2097620984 full_compact_gc_p = true;
2097720985 }
20978- else if ((current_total_committed * 10) >= (heap_hard_limit * 9))
20986+ else if (((uint64_t) current_total_committed * (uint64_t) 10) >= ((uint64_t) heap_hard_limit * (uint64_t) 9))
2097920987 {
2098020988 size_t loh_frag = get_total_gen_fragmentation (loh_generation);
2098120989
2098220990 // If the LOH frag is >= 1/8 it's worth compacting it
20983- if (( loh_frag * 8) >= heap_hard_limit)
20991+ if (loh_frag >= heap_hard_limit / 8 )
2098420992 {
2098520993 dprintf (GTC_LOG, ("loh frag: %zd > 1/8 of limit %zd", loh_frag, (heap_hard_limit / 8)));
2098620994 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_frag);
@@ -20991,7 +20999,7 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
2099120999 // If there's not much fragmentation but it looks like it'll be productive to
2099221000 // collect LOH, do that.
2099321001 size_t est_loh_reclaim = get_total_gen_estimated_reclaim (loh_generation);
20994- if (( est_loh_reclaim * 8) >= heap_hard_limit)
21002+ if (est_loh_reclaim >= heap_hard_limit / 8 )
2099521003 {
2099621004 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_reclaim);
2099721005 full_compact_gc_p = true;
@@ -43743,6 +43751,15 @@ void gc_heap::init_static_data()
4374343751 );
4374443752#endif //MULTIPLE_HEAPS
4374543753
43754+ #ifndef HOST_64BIT
43755+ if (heap_hard_limit)
43756+ {
43757+ size_t gen1_max_size_seg = soh_segment_size / 2;
43758+ dprintf (GTC_LOG, ("limit gen1 max %zd->%zd", gen1_max_size, gen1_max_size_seg));
43759+ gen1_max_size = min (gen1_max_size, gen1_max_size_seg);
43760+ }
43761+ #endif //!HOST_64BIT
43762+
4374643763 size_t gen1_max_size_config = (size_t)GCConfig::GetGCGen1MaxBudget();
4374743764
4374843765 if (gen1_max_size_config)
@@ -48868,6 +48885,11 @@ HRESULT GCHeap::Initialize()
4886848885 {
4886948886 if (gc_heap::heap_hard_limit)
4887048887 {
48888+ #ifndef HOST_64BIT
48889+ // Regions are not supported on 32bit
48890+ assert(false);
48891+ #endif //!HOST_64BIT
48892+
4887148893 if (gc_heap::heap_hard_limit_oh[soh])
4887248894 {
4887348895 gc_heap::regions_range = gc_heap::heap_hard_limit;
@@ -48902,12 +48924,32 @@ HRESULT GCHeap::Initialize()
4890248924 {
4890348925 if (gc_heap::heap_hard_limit_oh[soh])
4890448926 {
48927+ // On 32bit we have next guarantees:
48928+ // 0 <= seg_size_from_config <= 1Gb (from max_heap_hard_limit/2)
48929+ // 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)
48930+ // 0 <= heap_hard_limit_oh[loh] <= 1Gb or < 2Gb
48931+ // 0 <= heap_hard_limit_oh[poh] <= 1Gb or < 2Gb
48932+ // 0 <= large_seg_size <= 1Gb or <= 2Gb (alignment and round up)
48933+ // 0 <= pin_seg_size <= 1Gb or <= 2Gb (alignment and round up)
48934+ // 0 <= soh_segment_size + large_seg_size + pin_seg_size <= 4Gb
48935+ // 4Gb overflow is ok, because 0 size allocation will fail
4890548936 large_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[loh], nhp), seg_size_from_config);
4890648937 pin_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[poh], nhp), seg_size_from_config);
4890748938 }
4890848939 else
4890948940 {
48941+ // On 32bit we have next guarantees:
48942+ // 0 <= heap_hard_limit <= 1Gb (from gc_heap::compute_hard_limit)
48943+ // 0 <= soh_segment_size <= 1Gb
48944+ // 0 <= large_seg_size <= 1Gb
48945+ // 0 <= pin_seg_size <= 1Gb
48946+ // 0 <= soh_segment_size + large_seg_size + pin_seg_size <= 3Gb
48947+ #ifdef HOST_64BIT
4891048948 large_seg_size = gc_heap::use_large_pages_p ? gc_heap::soh_segment_size : gc_heap::soh_segment_size * 2;
48949+ #else //HOST_64BIT
48950+ assert (!gc_heap::use_large_pages_p);
48951+ large_seg_size = gc_heap::soh_segment_size;
48952+ #endif //HOST_64BIT
4891148953 pin_seg_size = large_seg_size;
4891248954 }
4891348955 if (gc_heap::use_large_pages_p)
@@ -53173,16 +53215,45 @@ int GCHeap::RefreshMemoryLimit()
5317353215 return gc_heap::refresh_memory_limit();
5317453216}
5317553217
53218+ bool gc_heap::compute_hard_limit_from_heap_limits()
53219+ {
53220+ #ifndef HOST_64BIT
53221+ // need to consider overflows:
53222+ 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)
53223+ || (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)
53224+ || (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)))
53225+ {
53226+ return false;
53227+ }
53228+ #endif //!HOST_64BIT
53229+
53230+ heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
53231+ return true;
53232+ }
53233+
53234+ // On 32bit we have next guarantees for limits:
53235+ // 1) heap-specific limits:
53236+ // 0 <= (heap_hard_limit = heap_hard_limit_oh[soh] + heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh]) < 4Gb
53237+ // a) 0 <= heap_hard_limit_oh[soh] < 2Gb, 0 <= heap_hard_limit_oh[loh] <= 1Gb, 0 <= heap_hard_limit_oh[poh] <= 1Gb
53238+ // b) 0 <= heap_hard_limit_oh[soh] <= 1Gb, 0 <= heap_hard_limit_oh[loh] < 2Gb, 0 <= heap_hard_limit_oh[poh] <= 1Gb
53239+ // c) 0 <= heap_hard_limit_oh[soh] <= 1Gb, 0 <= heap_hard_limit_oh[loh] <= 1Gb, 0 <= heap_hard_limit_oh[poh] < 2Gb
53240+ // 2) same limit for all heaps:
53241+ // 0 <= heap_hard_limit <= 1Gb
53242+ //
53243+ // These ranges guarantee that calculation of soh_segment_size, loh_segment_size and poh_segment_size with alignment and round up won't overflow,
53244+ // as well as calculation of sum of them (overflow to 0 is allowed, because allocation with 0 size will fail later).
5317653245bool gc_heap::compute_hard_limit()
5317753246{
5317853247 heap_hard_limit_oh[soh] = 0;
53179- #ifdef HOST_64BIT
53248+
5318053249 heap_hard_limit = (size_t)GCConfig::GetGCHeapHardLimit();
5318153250 heap_hard_limit_oh[soh] = (size_t)GCConfig::GetGCHeapHardLimitSOH();
5318253251 heap_hard_limit_oh[loh] = (size_t)GCConfig::GetGCHeapHardLimitLOH();
5318353252 heap_hard_limit_oh[poh] = (size_t)GCConfig::GetGCHeapHardLimitPOH();
5318453253
53254+ #ifdef HOST_64BIT
5318553255 use_large_pages_p = GCConfig::GetGCLargePages();
53256+ #endif //HOST_64BIT
5318653257
5318753258 if (heap_hard_limit_oh[soh] || heap_hard_limit_oh[loh] || heap_hard_limit_oh[poh])
5318853259 {
@@ -53194,8 +53265,10 @@ bool gc_heap::compute_hard_limit()
5319453265 {
5319553266 return false;
5319653267 }
53197- heap_hard_limit = heap_hard_limit_oh[soh] +
53198- heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
53268+ if (!compute_hard_limit_from_heap_limits())
53269+ {
53270+ return false;
53271+ }
5319953272 }
5320053273 else
5320153274 {
@@ -53223,9 +53296,22 @@ bool gc_heap::compute_hard_limit()
5322353296 heap_hard_limit_oh[soh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_soh / (uint64_t)100);
5322453297 heap_hard_limit_oh[loh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_loh / (uint64_t)100);
5322553298 heap_hard_limit_oh[poh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_poh / (uint64_t)100);
53226- heap_hard_limit = heap_hard_limit_oh[soh] +
53227- heap_hard_limit_oh[loh] + heap_hard_limit_oh[poh];
53299+
53300+ if (!compute_hard_limit_from_heap_limits())
53301+ {
53302+ return false;
53303+ }
5322853304 }
53305+ #ifndef HOST_64BIT
53306+ else
53307+ {
53308+ // need to consider overflows
53309+ if (heap_hard_limit > max_heap_hard_limit / 2)
53310+ {
53311+ return false;
53312+ }
53313+ }
53314+ #endif //!HOST_64BIT
5322953315 }
5323053316
5323153317 if (heap_hard_limit_oh[soh] && (!heap_hard_limit_oh[poh]) && (!use_large_pages_p))
@@ -53239,9 +53325,17 @@ bool gc_heap::compute_hard_limit()
5323953325 if ((percent_of_mem > 0) && (percent_of_mem < 100))
5324053326 {
5324153327 heap_hard_limit = (size_t)(total_physical_mem * (uint64_t)percent_of_mem / (uint64_t)100);
53328+
53329+ #ifndef HOST_64BIT
53330+ // need to consider overflows
53331+ if (heap_hard_limit > max_heap_hard_limit / 2)
53332+ {
53333+ return false;
53334+ }
53335+ #endif //!HOST_64BIT
5324253336 }
5324353337 }
53244- #endif //HOST_64BIT
53338+
5324553339 return true;
5324653340}
5324753341
@@ -53266,12 +53360,12 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
5326653360 }
5326753361 }
5326853362 }
53363+ #endif //HOST_64BIT
5326953364
5327053365 if (heap_hard_limit && (heap_hard_limit < new_current_total_committed))
5327153366 {
5327253367 return false;
5327353368 }
53274- #endif //HOST_64BIT
5327553369
5327653370#ifdef USE_REGIONS
5327753371 {
@@ -53290,9 +53384,24 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
5329053384 seg_size_from_config = (size_t)GCConfig::GetSegmentSize();
5329153385 if (seg_size_from_config)
5329253386 {
53293- seg_size_from_config = adjust_segment_size_hard_limit_va (seg_size_from_config);
53387+ seg_size_from_config = use_large_pages_p ? align_on_segment_hard_limit (seg_size_from_config) :
53388+ #ifdef HOST_64BIT
53389+ round_up_power2 (seg_size_from_config);
53390+ #else //HOST_64BIT
53391+ round_down_power2 (seg_size_from_config);
53392+ seg_size_from_config = min (seg_size_from_config, max_heap_hard_limit / 2);
53393+ #endif //HOST_64BIT
5329453394 }
5329553395
53396+ // On 32bit we have next guarantees:
53397+ // 0 <= seg_size_from_config <= 1Gb (from max_heap_hard_limit/2)
53398+ // a) heap-specific limits:
53399+ // 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)
53400+ // 0 <= heap_hard_limit_oh[soh] <= 1Gb or < 2Gb
53401+ // 0 <= soh_segment_size <= 1Gb or <= 2Gb (alignment and round up)
53402+ // b) same limit for all heaps:
53403+ // 0 <= heap_hard_limit <= 1Gb
53404+ // 0 <= soh_segment_size <= 1Gb
5329653405 size_t limit_to_check = (heap_hard_limit_oh[soh] ? heap_hard_limit_oh[soh] : heap_hard_limit);
5329753406 soh_segment_size = max (adjust_segment_size_hard_limit (limit_to_check, nhp), seg_size_from_config);
5329853407 }
0 commit comments