@@ -1919,7 +1919,16 @@ uint8_t* gc_heap::pad_for_alignment_large (uint8_t* newAlloc, int requiredAlignm
19191919#endif //BACKGROUND_GC && !USE_REGIONS
19201920
19211921// This is always power of 2.
1922+ #ifdef HOST_64BIT
19221923const 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
19231932
19241933inline
19251934size_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
72787287 *
72797288 * Note : We never commit into free directly, so bucket != recorded_committed_free_bucket
72807289 */
7281- #ifndef HOST_64BIT
7282- assert (heap_hard_limit == 0);
7283- #endif //!HOST_64BIT
7284-
72857290 assert(0 <= bucket && bucket < recorded_committed_bucket_counts);
72867291 assert(bucket < total_oh_count || h_number == -1);
72877292 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
73857390 * Case 2: This is for bookkeeping - the bucket will be recorded_committed_bookkeeping_bucket, and the h_number will be -1
73867391 * Case 3: This is for free - the bucket will be recorded_committed_free_bucket, and the h_number will be -1
73877392 */
7388- #ifndef HOST_64BIT
7389- assert (heap_hard_limit == 0);
7390- #endif //!HOST_64BIT
7391-
73927393 assert(0 <= bucket && bucket < recorded_committed_bucket_counts);
73937394 assert(bucket < total_oh_count || h_number == -1);
73947395
@@ -14167,6 +14168,11 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
1416714168 return E_OUTOFMEMORY;
1416814169 if (use_large_pages_p)
1416914170 {
14171+ #ifndef HOST_64BIT
14172+ // Large pages are not supported on 32bit
14173+ assert (false);
14174+ #endif //!HOST_64BIT
14175+
1417014176 if (heap_hard_limit_oh[soh])
1417114177 {
1417214178 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,
2077420780 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_before_oom);
2077520781 full_compact_gc_p = true;
2077620782 }
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))
2077820784 {
2077920785 size_t loh_frag = get_total_gen_fragmentation (loh_generation);
2078020786
2078120787 // 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 )
2078320789 {
2078420790 dprintf (GTC_LOG, ("loh frag: %zd > 1/8 of limit %zd", loh_frag, (heap_hard_limit / 8)));
2078520791 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,
2079020796 // If there's not much fragmentation but it looks like it'll be productive to
2079120797 // collect LOH, do that.
2079220798 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 )
2079420800 {
2079520801 gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_reclaim);
2079620802 full_compact_gc_p = true;
@@ -24369,7 +24375,7 @@ heap_segment* gc_heap::unlink_first_rw_region (int gen_idx)
2436924375 assert (!heap_segment_read_only_p (region));
2437024376 dprintf (REGIONS_LOG, ("unlink_first_rw_region on heap: %d gen: %d region: %p", heap_number, gen_idx, heap_segment_mem (region)));
2437124377
24372- #if defined(_DEBUG) && defined(HOST_64BIT)
24378+ #if defined(_DEBUG)
2437324379#ifndef COMMITTED_BYTES_SHADOW
2437424380 if (heap_hard_limit)
2437524381#endif //!COMMITTED_BYTES_SHADOW
@@ -24384,7 +24390,7 @@ heap_segment* gc_heap::unlink_first_rw_region (int gen_idx)
2438424390 g_heaps[old_heap]->committed_by_oh_per_heap[old_oh] -= committed;
2438524391 check_commit_cs.Leave();
2438624392 }
24387- #endif // _DEBUG && HOST_64BIT
24393+ #endif // _DEBUG
2438824394
2438924395 set_heap_for_contained_basic_regions (region, nullptr);
2439024396
@@ -24412,7 +24418,7 @@ void gc_heap::thread_rw_region_front (int gen_idx, heap_segment* region)
2441224418 }
2441324419 dprintf (REGIONS_LOG, ("thread_rw_region_front on heap: %d gen: %d region: %p", heap_number, gen_idx, heap_segment_mem (region)));
2441424420
24415- #if defined(_DEBUG) && defined(HOST_64BIT)
24421+ #if defined(_DEBUG)
2441624422#ifndef COMMITTED_BYTES_SHADOW
2441724423 if (heap_hard_limit)
2441824424#endif //!COMMITTED_BYTES_SHADOW
@@ -24427,7 +24433,7 @@ void gc_heap::thread_rw_region_front (int gen_idx, heap_segment* region)
2442724433 g_heaps[new_heap]->committed_by_oh_per_heap[new_oh] += committed;
2442824434 check_commit_cs.Leave();
2442924435 }
24430- #endif // _DEBUG && HOST_64BIT
24436+ #endif // _DEBUG
2443124437
2443224438 set_heap_for_contained_basic_regions (region, this);
2443324439}
@@ -43369,6 +43375,13 @@ void gc_heap::init_static_data()
4336943375 );
4337043376#endif //MULTIPLE_HEAPS
4337143377
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+
4337243385 size_t gen1_max_size_config = (size_t)GCConfig::GetGCGen1MaxBudget();
4337343386
4337443387 if (gen1_max_size_config)
@@ -48480,6 +48493,11 @@ HRESULT GCHeap::Initialize()
4848048493 {
4848148494 if (gc_heap::heap_hard_limit)
4848248495 {
48496+ #ifndef HOST_64BIT
48497+ // Regions are not supported on 32bit
48498+ assert(false);
48499+ #endif //!HOST_64BIT
48500+
4848348501 if (gc_heap::heap_hard_limit_oh[soh])
4848448502 {
4848548503 gc_heap::regions_range = gc_heap::heap_hard_limit;
@@ -48514,12 +48532,32 @@ HRESULT GCHeap::Initialize()
4851448532 {
4851548533 if (gc_heap::heap_hard_limit_oh[soh])
4851648534 {
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
4851748544 large_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[loh], nhp), seg_size_from_config);
4851848545 pin_seg_size = max (gc_heap::adjust_segment_size_hard_limit (gc_heap::heap_hard_limit_oh[poh], nhp), seg_size_from_config);
4851948546 }
4852048547 else
4852148548 {
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
4852248556 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
4852348561 pin_seg_size = large_seg_size;
4852448562 }
4852548563 if (gc_heap::use_large_pages_p)
@@ -52683,16 +52721,45 @@ int GCHeap::RefreshMemoryLimit()
5268352721 return gc_heap::refresh_memory_limit();
5268452722}
5268552723
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).
5268652751bool gc_heap::compute_hard_limit()
5268752752{
5268852753 heap_hard_limit_oh[soh] = 0;
52689- #ifdef HOST_64BIT
52754+
5269052755 heap_hard_limit = (size_t)GCConfig::GetGCHeapHardLimit();
5269152756 heap_hard_limit_oh[soh] = (size_t)GCConfig::GetGCHeapHardLimitSOH();
5269252757 heap_hard_limit_oh[loh] = (size_t)GCConfig::GetGCHeapHardLimitLOH();
5269352758 heap_hard_limit_oh[poh] = (size_t)GCConfig::GetGCHeapHardLimitPOH();
5269452759
52760+ #ifdef HOST_64BIT
5269552761 use_large_pages_p = GCConfig::GetGCLargePages();
52762+ #endif //HOST_64BIT
5269652763
5269752764 if (heap_hard_limit_oh[soh] || heap_hard_limit_oh[loh] || heap_hard_limit_oh[poh])
5269852765 {
@@ -52704,8 +52771,10 @@ bool gc_heap::compute_hard_limit()
5270452771 {
5270552772 return false;
5270652773 }
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+ }
5270952778 }
5271052779 else
5271152780 {
@@ -52733,9 +52802,22 @@ bool gc_heap::compute_hard_limit()
5273352802 heap_hard_limit_oh[soh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_soh / (uint64_t)100);
5273452803 heap_hard_limit_oh[loh] = (size_t)(total_physical_mem * (uint64_t)percent_of_mem_loh / (uint64_t)100);
5273552804 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+ }
5273852819 }
52820+ #endif //!HOST_64BIT
5273952821 }
5274052822
5274152823 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()
5274952831 if ((percent_of_mem > 0) && (percent_of_mem < 100))
5275052832 {
5275152833 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
5275252842 }
5275352843 }
52754- #endif //HOST_64BIT
52844+
5275552845 return true;
5275652846}
5275752847
@@ -52776,12 +52866,12 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
5277652866 }
5277752867 }
5277852868 }
52869+ #endif //HOST_64BIT
5277952870
5278052871 if (heap_hard_limit && (heap_hard_limit < new_current_total_committed))
5278152872 {
5278252873 return false;
5278352874 }
52784- #endif //HOST_64BIT
5278552875
5278652876#ifdef USE_REGIONS
5278752877 {
@@ -52800,9 +52890,24 @@ bool gc_heap::compute_memory_settings(bool is_initialization, uint32_t& nhp, uin
5280052890 seg_size_from_config = (size_t)GCConfig::GetSegmentSize();
5280152891 if (seg_size_from_config)
5280252892 {
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
5280452900 }
5280552901
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
5280652911 size_t limit_to_check = (heap_hard_limit_oh[soh] ? heap_hard_limit_oh[soh] : heap_hard_limit);
5280752912 soh_segment_size = max (adjust_segment_size_hard_limit (limit_to_check, nhp), seg_size_from_config);
5280852913 }
0 commit comments