• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/base/ui_node_gc.h"
17 
18 #include "base/utils/time_util.h"
19 #include "core/components_ng/base/ui_node.h"
20 #include "core/pipeline/pipeline_base.h"
21 
22 namespace OHOS::Ace::NG {
23 namespace {
24 enum {
25     PRIORITYTYPE_WATERLINE_LOW = 50,
26     PRIORITYTYPE_WATERLINE_HIGH = 100,
27     PRIORITYTYPE_WATERLINE_IMMEDIATE = 500,
28     PRIORITYTYPE_WATERLINE_VIP,
29 };
30 constexpr size_t PER_BUCKET_MAX_SIZE = 10;
31 constexpr size_t BUCKET_MAX_SIZE = 1000;
32 thread_local int64_t deadline_ = -1;
33 thread_local std::queue<std::vector<OHOS::Ace::NG::UINode*>> nodeRawBucket_;
34 } // namespace
35 
IsTooLate(int64_t deadline)36 bool UiNodeGc::IsTooLate(int64_t deadline)
37 {
38     if (deadline == -1) {
39         return false;
40     }
41 
42     return GetSysTimestamp() > deadline;
43 }
44 
PostTask(const RefPtr<TaskExecutor> & taskExecutor,const TaskExecutor::Task & task,const std::string & name,PriorityType priorityType)45 bool UiNodeGc::PostTask(const RefPtr<TaskExecutor>& taskExecutor, const TaskExecutor::Task& task,
46     const std::string& name, PriorityType priorityType)
47 {
48     if (taskExecutor) {
49         taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name, priorityType);
50         return true;
51     }
52     LOGW("UiNodeGc::PostTask failed");
53     task();
54     return false;
55 }
56 
ReleaseInner(OHOS::Ace::NG::UINode * rawPtr)57 void UiNodeGc::ReleaseInner(OHOS::Ace::NG::UINode* rawPtr)
58 {
59     if (nodeRawBucket_.empty()) {
60         nodeRawBucket_.push({ rawPtr });
61         return;
62     }
63     auto& bucket = nodeRawBucket_.back();
64     if (bucket.size() >= PER_BUCKET_MAX_SIZE) {
65         nodeRawBucket_.push({ rawPtr });
66         return;
67     }
68     bucket.push_back(rawPtr);
69 }
70 
ReleaseNodeRawBucket()71 void UiNodeGc::ReleaseNodeRawBucket()
72 {
73     if (nodeRawBucket_.empty()) {
74         return;
75     }
76     std::vector<OHOS::Ace::NG::UINode*> toDele = std::move(nodeRawBucket_.front());
77     nodeRawBucket_.pop();
78     ACE_SCOPED_TRACE_COMMERCIAL(
79         "ReleaseNodeRawBucket delete %zu, remain node buckets %zu", toDele.size(), nodeRawBucket_.size());
80     for (auto ptr : toDele) {
81         if (ptr) {
82             delete ptr;
83         }
84     }
85 }
86 
JudgeGCLevel(uint32_t remainBucketSize,int64_t deadline)87 PriorityType UiNodeGc::JudgeGCLevel(uint32_t remainBucketSize, int64_t deadline)
88 {
89     if (deadline == -1) {
90         //  we don't know next frame idle
91         return PriorityType::IDLE;
92     }
93 
94     if (remainBucketSize < PRIORITYTYPE_WATERLINE_LOW) {
95         return PriorityType::LOW;
96     } else if (remainBucketSize < PRIORITYTYPE_WATERLINE_HIGH) {
97         return PriorityType::HIGH;
98     } else if (remainBucketSize < PRIORITYTYPE_WATERLINE_IMMEDIATE) {
99         return PriorityType::IMMEDIATE;
100     }
101     return PriorityType::VIP;
102 }
103 
PostReleaseNodeRawMemoryTask(const RefPtr<TaskExecutor> & taskExecutor)104 void UiNodeGc::PostReleaseNodeRawMemoryTask(const RefPtr<TaskExecutor>& taskExecutor)
105 {
106     if (!taskExecutor) {
107         LOGE("UiNodeGc::PostReleaseNodeRawMemoryTask taskExecutor is nullptr");
108         return;
109     }
110     ReleaseNodeRawMemory(-1, taskExecutor);
111 }
112 
ReleaseNodeRawMemoryInner(const RefPtr<TaskExecutor> & taskExecutor)113 void UiNodeGc::ReleaseNodeRawMemoryInner(const RefPtr<TaskExecutor>& taskExecutor)
114 {
115     if (nodeRawBucket_.empty()) {
116         return;
117     }
118     auto remainBucketSize = nodeRawBucket_.size();
119     auto nodeGCLevel = JudgeGCLevel(remainBucketSize, deadline_);
120     auto task = [nodeGCLevel, remainBucketSize, taskExecutor = taskExecutor]() {
121         if (IsTooLate(deadline_) && nodeGCLevel != PriorityType::VIP) {
122             return;
123         }
124         ReleaseNodeRawBucket();
125         ReleaseNodeRawMemoryInner(taskExecutor);
126     };
127     PostTask(taskExecutor, task, "ReleaseNodeRawMemoryTask", nodeGCLevel);
128 }
129 
ReleaseNodeRawMemory(int64_t deadline,const RefPtr<TaskExecutor> & taskExecutor)130 void UiNodeGc::ReleaseNodeRawMemory(int64_t deadline, const RefPtr<TaskExecutor>& taskExecutor)
131 {
132     deadline_ = deadline;
133     UiNodeGc::ReleaseNodeRawMemoryInner(taskExecutor);
134 }
135 
OnReleaseFunc(OHOS::Ace::NG::UINode * rawPtr)136 void UiNodeGc::OnReleaseFunc(OHOS::Ace::NG::UINode* rawPtr)
137 {
138     if (!rawPtr) {
139         LOGE("UiNodeGc::OnReleaseFunc rawPtr is nullptr");
140         return;
141     }
142 
143     if (nodeRawBucket_.size() > BUCKET_MAX_SIZE) {
144         LOGW("UiNodeGc::OnReleaseFunc nodeRawBucket size is %{public}zu", nodeRawBucket_.size());
145         delete rawPtr;
146         return;
147     }
148 
149     rawPtr->OnDelete();
150     ReleaseInner(rawPtr);
151 }
152 
MockGetNodeRawBucket()153 std::queue<std::vector<OHOS::Ace::NG::UINode*>>& UiNodeGc::MockGetNodeRawBucket()
154 {
155     return nodeRawBucket_;
156 }
157 } // namespace OHOS::Ace::NG
158