-
Notifications
You must be signed in to change notification settings - Fork 4.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
region memory limit #48691
region memory limit #48691
Conversation
Tagging subscribers to this area: @dotnet/gc Issue Details
|
src/coreclr/gc/gc.cpp
Outdated
num_heaps = n_heaps; | ||
#endif //MULTIPLE_HEAPS | ||
left_in_commit /= num_heaps; | ||
if (left_in_commit <= space_required) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this just be <
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, will change it.
@@ -3571,7 +3571,7 @@ uint8_t* region_allocator::allocate (uint32_t num_units) | |||
uint32_t* current_index = region_map_start; | |||
uint32_t* end_index = region_map_end; | |||
|
|||
dprintf (1, ("\nsearcing %d->%d", (int)(current_index - region_map_start), (int)(end_index - region_map_start))); | |||
dprintf (1, ("searching %d->%d", (int)(current_index - region_map_start), (int)(end_index - region_map_start))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the dprintf level be REGIONS_LOG here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will change all of the dprintf's in region_allocator to REGIONS_LOG.
from = align_lower_segment (from); | ||
end = align_on_segment (end); | ||
dprintf (1, ("from: %Ix, end: %Ix, size: %Ix", from, end, sizeof (seg_mapping)*(((size_t)(end - from) >> gc_heap::min_segment_size_shr)))); | ||
dprintf (1, ("from: %Ix, end: %Ix, size: %Ix", from, end, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use dprintf level REGIONS_LOG here as well?
region = allocate_new_region (__this, 0, false); | ||
if (region) | ||
{ | ||
init_table_for_region (0, region); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about the case where init_table_for_region fails because the mark array cannot be committed? It seems that we would return true in this case, but likely still fail when we later try to get the region.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch! I did check for this (I set region to 0 in init_table_for_region
when we can't commit) but I made a mistake when I refactored it out to its own method. should have init_table_for_region
return false if we can't commit.
|
||
if (gen_number <= max_generation) | ||
{ | ||
size_t first_brick = brick_of (heap_segment_mem (region)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this AV if commit_mark_array_new_seg failed above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it wouldn't - right now the GC bookkeeping datastructure is completely committed for the region's range except for the mark array part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but above, you set region to 0, so as heap_segment_mem dereferences it, you would AV before you even get to the brick_of part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh I misunderstood your intention for the question...absolutely, I shouldn't call this when the region is already set to 0
} | ||
else | ||
{ | ||
assert (brick_table[brick_of (heap_segment_mem (region))] == 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
I found a problem with aging handles for the special sweep case. will fix it later today. |
src/coreclr/gc/gcpriv.h
Outdated
@@ -3364,7 +3377,7 @@ class gc_heap | |||
PER_HEAP | |||
int pinning_seg_interval; | |||
PER_HEAP | |||
int num_gen0_segs; | |||
int num_gen0_regions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this could be a local variable instead of a field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I specifically wanted this to be a global so it introduces some variation instead of always pinning the 1st, 3rd, etc gen0 region. but I changed it to size_t instead of int.
src/coreclr/gc/gc.cpp
Outdated
|
||
if ((num_gen0_regions % pinning_seg_interval) == 0) | ||
{ | ||
int align_const = get_alignment_constant (TRUE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be helpful to put a comment, e.g. "Pin one object at the beginning".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added.
src/coreclr/gc/gc.cpp
Outdated
uint8_t* obj_to_pin = heap_segment_mem (gen0_region); | ||
pin_by_gc (obj_to_pin); | ||
|
||
obj_to_pin += Align (size (obj_to_pin), align_const); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto: "Pin one object near the middle".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added.
src/coreclr/gc/gc.cpp
Outdated
@@ -18218,6 +18243,14 @@ int gc_heap::generation_to_condemn (int n_initial, | |||
} | |||
} | |||
|
|||
#ifdef USE_REGIONS | |||
if (!try_get_new_free_region()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why we need a new free region here - could you explain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's to prepare for possibly needing to get a new region for gen0 in the later phases.
src/coreclr/gc/gc.cpp
Outdated
#ifdef USE_REGIONS | ||
if (!try_get_new_free_region()) | ||
{ | ||
dprintf (GTC_LOG, ("can't get an empty region -> full compacting")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In your comments for the PR, you said in this case we will do a special kind of sweep. The dprintf says we do a full compacting GC. Is there a contradiction, or what am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's the "and find out that we do need it," part - we try to get a new region here just to prepare for if we need it, as long as we don't actually need it, we will be doing a full compacting GC. but if we can't get it here and later find that we actually need it that's when we absolute run out of memory and we only do the special sweep then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks!
} | ||
} | ||
|
||
void gc_heap::process_remaining_regions (int current_plan_gen_num, generation* consing_gen) | ||
{ | ||
assert ((current_plan_gen_num == 0) || (!settings.promotion && (current_plan_gen_num == -1))); | ||
|
||
if (special_sweep_p) | ||
{ | ||
assert (pinned_plug_que_empty_p()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you put a comment why this should be true?
{ | ||
dprintf (REGIONS_LOG, ("h%d couldn't get a region to plan gen0, special sweep on", | ||
heap_number)); | ||
special_sweep_p = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be good to put a comment explaining how the special sweep mode works, i.e. what's special about it.
+ implemented the logic to handle when we are really running out of memory. We need to be resilient to it during a GC. We might need an empty region per heap so we try to get it up front and if we can't get it and find out that we do need it, we resort to a special sweep mode. + also take virtual memory load into consideration + fixed the logic to decide whether we should compact based on space. + fixed various places when we can't get a region, we need to make sure we don't thread 0 into the region list. + made allocated_since_last_gc per more_space_lock otherwise we are not doing the accounting correctly + moved the pinning for STRESS_REGIONS into a blocking GC otherwise we can have AV from BGC trying to mark the pinned object while it's being constructed + got rid of the places that use the hard coded REGION_SIZE + included one perf change in reset_memory
247995b
to
f532c41
Compare
We need to be resilient to it during a GC. We might need an empty region
per heap so we try to get it up front and if we can't get it and find out
that we do need it, we resort to a special sweep mode.
don't thread 0 into the region list.
the accounting correctly
AV from BGC trying to mark the pinned object while it's being constructed