Fix for freelist pool memory fragment

issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I62K33?from=project-issue

Signed-off-by: maojunwei <maojunwei1@huawei.com>
Change-Id: Ib64a16eb988c7c222952f3ca52d14bffb24a60ed
This commit is contained in:
maojunwei 2022-11-29 10:56:57 +08:00
parent 0875afa157
commit 09d2070b16
3 changed files with 135 additions and 4 deletions

View File

@ -18,6 +18,7 @@
#include <deque>
#include <map>
#include <set>
#include "ecmascript/platform/map.h"
#include "ecmascript/mem/mem.h"
@ -107,11 +108,37 @@ public:
{
PageUnmap(memMap_);
freeList_.clear();
freeSet_.clear();
}
NO_COPY_SEMANTIC(MemMapFreeList);
NO_MOVE_SEMANTIC(MemMapFreeList);
void MergeList()
{
auto it = freeList_.begin();
while (it != freeList_.end()) {
bool isEqual = false;
void *startMem = (*it).second.GetMem();
size_t newSize = (*it).second.GetSize();
auto startIt = it++;
if (it == freeList_.end()) {
break;
}
auto next = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(startMem) + newSize);
while (it != freeList_.end() && next == (*it).second.GetMem()) {
newSize += (*it).second.GetSize();
freeList_.erase(it++);
next = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(startMem) + newSize);
isEqual = true;
}
if (isEqual) {
freeList_.erase(startIt);
freeList_.emplace(newSize, MemMap(startMem, newSize));
}
}
}
MemMap GetMemFromList(size_t size)
{
if (freeListPoolSize_ + size > capacity_) {
@ -121,8 +148,19 @@ public:
os::memory::LockHolder lock(lock_);
auto iterate = freeList_.lower_bound(size);
if (iterate == freeList_.end()) {
LOG_GC(ERROR) << "Freelist pool oom: memory fragment(" << freeListPoolSize_ << ")";
return MemMap();
MergeList();
iterate = freeList_.lower_bound(size);
// Unable to get memory from freeList, use PageMap
if (iterate == freeList_.end()) {
if (freeListPoolSize_ + freeSetPoolSize_ + size > capacity_) {
LOG_GC(ERROR) << "Freeset pool oom: overflow(" << freeSetPoolSize_ << ")";
return MemMap();
}
MemMap smemMap = PageMap(size, PAGE_PROT_NONE, DEFAULT_REGION_SIZE);
freeSet_.emplace(reinterpret_cast<uintptr_t>(smemMap.GetMem()));
freeSetPoolSize_ += size;
return smemMap;
}
}
MemMap memMap = iterate->second;
size_t remainderSize = memMap.GetSize() - size;
@ -138,15 +176,24 @@ public:
void AddMemToList(MemMap memMap)
{
os::memory::LockHolder lock(lock_);
freeListPoolSize_ -= memMap.GetSize();
freeList_.emplace(memMap.GetSize(), memMap);
auto search = freeSet_.find(reinterpret_cast<uintptr_t>(memMap.GetMem()));
if (UNLIKELY(search != freeSet_.end())) {
freeSetPoolSize_ -= memMap.GetSize();
freeSet_.erase(search);
PageUnmap(memMap);
} else {
freeListPoolSize_ -= memMap.GetSize();
freeList_.emplace(memMap.GetSize(), memMap);
}
}
private:
os::memory::Mutex lock_;
MemMap memMap_;
std::multimap<size_t, MemMap> freeList_;
std::set<uintptr_t> freeSet_;
std::atomic_size_t freeListPoolSize_ {0};
std::atomic_size_t freeSetPoolSize_ {0};
size_t capacity_ {0};
};

View File

@ -156,6 +156,7 @@ host_unittest_action("EcmaVm_003_Test") {
"linked_hash_table_test.cpp",
"linked_node_test.cpp",
"mem_controller_test.cpp",
"mem_map_allocator_test.cpp",
"native_pointer_test.cpp",
"object_factory_test.cpp",
"object_operator_test.cpp",

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/ecma_vm.h"
#include "ecmascript/mem/mem_map_allocator.h"
#include "ecmascript/mem/mem_common.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::base;
namespace panda::test {
constexpr size_t HUGE_OBJECT_CAPACITY = 512_KB;
class MemMapAllocatorTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
};
HWTEST_F_L0(MemMapAllocatorTest, GetMemFromList)
{
MemMap memMap = PageMap(HUGE_OBJECT_CAPACITY, PAGE_PROT_NONE, DEFAULT_REGION_SIZE);
PageRelease(memMap.GetMem(), memMap.GetSize());
MemMapFreeList memMapFreeList_;
memMapFreeList_.Initialize(memMap);
// From FreeList
size_t size1 = 256 * 1024;
auto mem1 = memMapFreeList_.GetMemFromList(size1);
EXPECT_EQ(mem1.GetSize(), size1);
// From FreeList
size_t size2 = 128 * 1024;
auto mem2 = memMapFreeList_.GetMemFromList(size2);
EXPECT_EQ(mem2.GetSize(), size2);
// From PageMap
size_t size3 = 128 * 1024;
auto mem3 = memMapFreeList_.GetMemFromList(size3);
EXPECT_EQ(mem3.GetSize(), size3);
memMapFreeList_.AddMemToList(mem3);
memMapFreeList_.Finalize();
}
} // namespace panda::test