From 57de2d5ef3e13eb37fc97a4cb08e03ab33c3b7f2 Mon Sep 17 00:00:00 2001 From: Caoruihong Date: Mon, 8 Sep 2025 22:54:43 +0800 Subject: [PATCH] support release rsnode on window hide to save memory Signed-off-by: Caoruihong --- adapter/ohos/osal/system_properties.cpp | 5 ++ adapter/preview/osal/system_properties.cpp | 5 ++ frameworks/base/utils/system_properties.h | 1 + .../manager/memory/memory_manager.cpp | 56 +++++++++++++++++++ .../render/adapter/rosen_render_context.cpp | 8 +++ .../render/adapter/rosen_render_context.h | 1 + .../components_ng/render/render_context.h | 1 + .../core/pipeline/base/element_register.cpp | 9 +++ .../core/pipeline/base/element_register.h | 1 + test/mock/base/mock_system_properties.cpp | 5 ++ test/mock/core/common/mock_window.cpp | 2 + .../core/pipeline/mock_element_register.cpp | 9 +++ 12 files changed, 103 insertions(+) diff --git a/adapter/ohos/osal/system_properties.cpp b/adapter/ohos/osal/system_properties.cpp index 5d3599d61be..76d7ad14e88 100644 --- a/adapter/ohos/osal/system_properties.cpp +++ b/adapter/ohos/osal/system_properties.cpp @@ -1441,6 +1441,11 @@ int32_t SystemProperties::getFormSharedImageCacheThreshold() return formSharedImageCacheThreshold_; } +bool SystemProperties::IsReleaseRenderNodeEnabled() +{ + return system::GetBoolParameter("persist.ace.release_render_node.enable", false); +} + bool SystemProperties::IsWhiteBlockEnabled() { return whiteBlockEnabled_; diff --git a/adapter/preview/osal/system_properties.cpp b/adapter/preview/osal/system_properties.cpp index 3795e89e735..5ed683534e8 100644 --- a/adapter/preview/osal/system_properties.cpp +++ b/adapter/preview/osal/system_properties.cpp @@ -492,6 +492,11 @@ void SystemProperties::SetMultiInstanceEnabled(bool enabled) { } +bool SystemProperties::IsReleaseRenderNodeEnabled() +{ + return false; +} + bool SystemProperties::IsWhiteBlockEnabled() { return false; diff --git a/frameworks/base/utils/system_properties.h b/frameworks/base/utils/system_properties.h index 50b65264eab..74ce364acd6 100644 --- a/frameworks/base/utils/system_properties.h +++ b/frameworks/base/utils/system_properties.h @@ -802,6 +802,7 @@ public: static int32_t getFormSharedImageCacheThreshold(); + static bool IsReleaseRenderNodeEnabled(); static bool IsWhiteBlockEnabled(); static bool IsWhiteBlockIdleChange(); static int32_t GetWhiteBlockIndexValue(); diff --git a/frameworks/core/components_ng/manager/memory/memory_manager.cpp b/frameworks/core/components_ng/manager/memory/memory_manager.cpp index 82c6053aa78..f26dd0a286f 100644 --- a/frameworks/core/components_ng/manager/memory/memory_manager.cpp +++ b/frameworks/core/components_ng/manager/memory/memory_manager.cpp @@ -21,6 +21,61 @@ namespace { constexpr int32_t BACKGROUND_RECYCLE_WAIT_TIME_MS = 500; constexpr int32_t RECYCLE_PAGE_IMAGE_NUM = 20; + +using namespace OHOS::Ace; + +void ReleaseRenderNodes(const RefPtr& element) +{ + auto frameNode = AceType::DynamicCast(element); + if (!frameNode) { + return; + } + auto pipeline = NG::PipelineContext::GetCurrentContext(); + if (frameNode->GetContextRefPtr() && frameNode->GetContextRefPtr() != pipeline) { + return; + } + auto renderContent = frameNode->GetRenderContext(); + if (!renderContent) { + return; + } + renderContent->ReleaseRenderNode(); +} + +void ReleaseRenderNodesTask() +{ + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto window = pipeline->GetWindow(); + CHECK_NULL_VOID(window); + if (pipeline->GetOnShow()) { + return; + } + ElementRegister::GetInstance()->IterateElements([](ElementIdType t, const RefPtr& e) { + ReleaseRenderNodes(e); + return false; + }); + window->SetForceVsyncRequests(true); + window->RequestFrame(); +} + +void PostReleaseRenderNodesTask() +{ + if (!SystemProperties::IsReleaseRenderNodeEnabled()) { + return; + } + auto container = Container::Current(); + if (container && container->IsSceneBoardWindow()) { + return; + } + auto pipeline = PipelineContext::GetCurrentContext(); + CHECK_NULL_VOID(pipeline); + auto taskExecutor = pipeline->GetTaskExecutor(); + CHECK_NULL_VOID(taskExecutor); + taskExecutor->PostDelayedTask(ReleaseRenderNodesTask, + TaskExecutor::TaskType::UI, + BACKGROUND_RECYCLE_WAIT_TIME_MS, + "ReleaseRenderNodesTask"); +} } namespace OHOS::Ace::NG { MemoryManager::MemoryManager() @@ -118,6 +173,7 @@ void MemoryManager::RebuildImage(const RefPtr& node) void MemoryManager::PostMemRecycleTask() { + PostReleaseRenderNodesTask(); auto container = Container::Current(); if (!isTrimMemWork_ || (container && container->IsSceneBoardWindow())) { return; diff --git a/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp b/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp index b6354470ec8..63c88e5b6a1 100755 --- a/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp +++ b/frameworks/core/components_ng/render/adapter/rosen_render_context.cpp @@ -5308,6 +5308,14 @@ void RosenRenderContext::SetClipBoundsWithCommands(const std::string& commands) rsNode_->SetClipBounds(Rosen::RSPath::CreateRSPath(rsPath)); } +void RosenRenderContext::ReleaseRenderNode() +{ + if (!rsNode_ || rsNode_->GetIsOnTheTree()) { + return; + } + rsNode_->ReleaseRenderNode(); +} + void RosenRenderContext::ClipWithRect(const RectF& rectF) { CHECK_NULL_VOID(rsNode_); diff --git a/frameworks/core/components_ng/render/adapter/rosen_render_context.h b/frameworks/core/components_ng/render/adapter/rosen_render_context.h index 12560952d99..5148a267432 100755 --- a/frameworks/core/components_ng/render/adapter/rosen_render_context.h +++ b/frameworks/core/components_ng/render/adapter/rosen_render_context.h @@ -380,6 +380,7 @@ public: void BuildPositionInfo(std::unique_ptr& json); void BuildShadowInfo(std::unique_ptr& json); void SetClipBoundsWithCommands(const std::string& commands) override; + void ReleaseRenderNode() override; void SetNeedDebugBoundary(bool flag) override { needDebugBoundary_ = flag; diff --git a/frameworks/core/components_ng/render/render_context.h b/frameworks/core/components_ng/render/render_context.h index a42986e5c94..b5c6c684a71 100644 --- a/frameworks/core/components_ng/render/render_context.h +++ b/frameworks/core/components_ng/render/render_context.h @@ -109,6 +109,7 @@ public: virtual void SetHostNode(const WeakPtr& host); RefPtr GetHost() const; + virtual void ReleaseRenderNode() {} virtual void SetNeedDebugBoundary(bool flag) {} virtual bool NeedDebugBoundary() const { diff --git a/frameworks/core/pipeline/base/element_register.cpp b/frameworks/core/pipeline/base/element_register.cpp index 0f8a5dfcdc2..8c8fadd0d35 100644 --- a/frameworks/core/pipeline/base/element_register.cpp +++ b/frameworks/core/pipeline/base/element_register.cpp @@ -35,6 +35,15 @@ ElementRegister* ElementRegister::GetInstance() return (ElementRegister::instance_); } +void ElementRegister::IterateElements(const std::function&)>& visitor) const +{ + for (auto& [k, v] : itemMap_) { + if (visitor(k, v.Upgrade())) { + break; + } + } +} + ElementIdType ElementRegister::MakeUniqueId() { return ElementRegister::nextUniqueElementId_++; diff --git a/frameworks/core/pipeline/base/element_register.h b/frameworks/core/pipeline/base/element_register.h index 165a5f74198..ea6c907805e 100644 --- a/frameworks/core/pipeline/base/element_register.h +++ b/frameworks/core/pipeline/base/element_register.h @@ -47,6 +47,7 @@ public: static constexpr ElementIdType UndefinedElementId = static_cast(-1); ACE_FORCE_EXPORT static ElementRegister* GetInstance(); + void IterateElements(const std::function&)>& visitor) const; RefPtr GetElementById(ElementIdType elementId); RefPtr GetElementProxyById(ElementIdType elementId); diff --git a/test/mock/base/mock_system_properties.cpp b/test/mock/base/mock_system_properties.cpp index c5ee61f1299..5428f6b8b9f 100644 --- a/test/mock/base/mock_system_properties.cpp +++ b/test/mock/base/mock_system_properties.cpp @@ -379,6 +379,11 @@ int32_t SystemProperties::getFormSharedImageCacheThreshold() return formSharedImageCacheThreshold_; } +bool SystemProperties::IsReleaseRenderNodeEnabled() +{ + return false; +} + bool SystemProperties::IsWhiteBlockEnabled() { return false; diff --git a/test/mock/core/common/mock_window.cpp b/test/mock/core/common/mock_window.cpp index 4552f9037d9..ef13f6e937d 100644 --- a/test/mock/core/common/mock_window.cpp +++ b/test/mock/core/common/mock_window.cpp @@ -22,6 +22,8 @@ void Window::OnVsync(uint64_t nanoTimestamp, uint64_t frameCount) {} void Window::RequestFrame() {} +void Window::SetForceVsyncRequests(bool forceVsyncRequests) {} + void Window::SetRootRenderNode(const RefPtr& root) {} void Window::SetVsyncCallback(AceVsyncCallback&& callback) {} diff --git a/test/mock/core/pipeline/mock_element_register.cpp b/test/mock/core/pipeline/mock_element_register.cpp index 9cc020ae344..a8f7d071038 100644 --- a/test/mock/core/pipeline/mock_element_register.cpp +++ b/test/mock/core/pipeline/mock_element_register.cpp @@ -36,6 +36,15 @@ ElementRegister* ElementRegister::GetInstance() return (ElementRegister::instance_); } +void ElementRegister::IterateElements(const std::function&)>& visitor) const +{ + for (auto& [k, v] : itemMap_) { + if (visitor(k, v.Upgrade())) { + break; + } + } +} + ElementIdType ElementRegister::MakeUniqueId() { return ElementRegister::nextUniqueElementId_++; -- Gitee