8234328: VectorSet::clear can cause fragmentation

Reviewed-by: neliasso
This commit is contained in:
Claes Redestad 2019-12-12 14:22:50 +01:00
parent 5ca3e6334a
commit 40bbdf472c
2 changed files with 23 additions and 33 deletions

View File

@ -31,17 +31,20 @@
VectorSet::VectorSet(Arena *arena) : _size(2),
_data(NEW_ARENA_ARRAY(arena, uint32_t, 2)),
_data_size(2),
_set_arena(arena) {
_data[0] = 0;
_data[1] = 0;
}
// Expand the existing set to a bigger size
void VectorSet::grow(uint new_size) {
new_size = (new_size + bit_mask) >> word_bits;
assert(new_size > 0, "sanity");
uint x = next_power_of_2(new_size);
_data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, x);
void VectorSet::grow(uint new_word_capacity) {
assert(new_word_capacity < (1U << 30), "");
uint x = next_power_of_2(new_word_capacity);
if (x > _data_size) {
_data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, x);
_data_size = x;
}
Copy::zero_to_bytes(_data + _size, (x - _size) * sizeof(uint32_t));
_size = x;
}
@ -51,20 +54,11 @@ void VectorSet::insert(uint elem) {
uint32_t word = elem >> word_bits;
uint32_t mask = 1U << (elem & bit_mask);
if (word >= _size) {
grow(elem + 1);
grow(word);
}
_data[word] |= mask;
}
// Resets the storage
void VectorSet::reset_memory() {
assert(_size >= 2, "_size can never be less than 2");
_data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, 2);
_size = 2;
_data[0] = 0;
_data[1] = 0;
}
// Return true if the set is empty
bool VectorSet::is_empty() const {
for (uint32_t i = 0; i < _size; i++) {

View File

@ -40,12 +40,15 @@ private:
static const uint word_bits = 5;
static const uint bit_mask = 31;
uint _size; // Size of data in 32-bit words
uint32_t* _data; // The data, bit packed
// Used 32-bit words
uint _size;
uint32_t* _data;
// Allocated words
uint _data_size;
Arena* _set_arena;
void grow(uint newsize); // Grow vector to required bitsize
void reset_memory();
// Grow vector to required word capacity
void grow(uint new_word_capacity);
public:
VectorSet(Arena *arena);
~VectorSet() {}
@ -53,15 +56,10 @@ public:
void insert(uint elem);
bool is_empty() const;
void reset() {
Copy::zero_to_bytes(_data, _size * sizeof(uint32_t));
_size = 0;
}
void clear() {
// Reclaim storage if huge
if (_size > 100) {
reset_memory();
} else {
reset();
}
reset();
}
// Fast inlined "test and set". Replaces the idiom:
@ -73,9 +71,8 @@ public:
bool test_set(uint elem) {
uint32_t word = elem >> word_bits;
if (word >= _size) {
// Then grow; set; return 0;
this->insert(elem);
return false;
// Then grow
grow(word);
}
uint32_t mask = 1U << (elem & bit_mask);
uint32_t data = _data[word];
@ -106,11 +103,10 @@ public:
void set(uint elem) {
uint32_t word = elem >> word_bits;
if (word >= _size) {
this->insert(elem);
} else {
uint32_t mask = 1U << (elem & bit_mask);
_data[word] |= mask;
grow(word);
}
uint32_t mask = 1U << (elem & bit_mask);
_data[word] |= mask;
}
};