1 /*
2 * Copyright (c) 2021 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 "base/memory/memory_monitor.h"
17
18 #include <map>
19 #include <mutex>
20
21 #if !defined(WINDOWS_PLATFORM) and !defined(MAC_PLATFORM) and !defined(IOS_PLATFORM) and !defined(LINUX_PLATFORM)
22 #include <malloc.h>
23 #endif
24
25 #include "base/log/dump_log.h"
26 #include "base/log/log.h"
27 #include "base/utils/system_properties.h"
28
29 namespace OHOS::Ace {
30
PurgeMallocCache()31 void PurgeMallocCache()
32 {
33 #if !defined(WINDOWS_PLATFORM) and !defined(MAC_PLATFORM) and !defined(IOS_PLATFORM) and !defined(LINUX_PLATFORM)
34 #if defined(__BIONIC__)
35 mallopt(M_PURGE, 0);
36 #endif
37 #endif
38 }
39
40 bool MemoryMonitor::isEnable_ = SystemProperties::GetIsUseMemoryMonitor();
41
42 class MemoryMonitorImpl : public MemoryMonitor {
43 public:
Add(void * ptr)44 void Add(void* ptr) final
45 {
46 std::lock_guard<std::mutex> lock(mutex_);
47 auto result = memoryMap_.emplace(ptr, MemInfo());
48 if (!result.second) {
49 LOGE("Address is already in memory map");
50 return;
51 }
52
53 count_++;
54 }
55
Remove(void * ptr)56 void Remove(void* ptr) final
57 {
58 std::lock_guard<std::mutex> lock(mutex_);
59 auto it = memoryMap_.find(ptr);
60 if (it == memoryMap_.end()) {
61 LOGE("Address MUST be in memory map");
62 return;
63 }
64 count_--;
65
66 if (it->second.size > 0) {
67 total_ -= it->second.size;
68 auto& info = typeMap_[it->second.typeName];
69 info.count--;
70 info.total -= it->second.size;
71 }
72 memoryMap_.erase(it);
73 }
74
Update(void * ptr,size_t size,const std::string & typeName)75 void Update(void* ptr, size_t size, const std::string& typeName) final
76 {
77 std::lock_guard<std::mutex> lock(mutex_);
78 auto it = memoryMap_.find(ptr);
79 if (it == memoryMap_.end()) {
80 LOGE("Address MUST be in memory map");
81 return;
82 }
83
84 it->second.size = size;
85 it->second.typeName = typeName;
86
87 total_ += size;
88 auto& info = typeMap_[typeName];
89 info.count++;
90 info.total += size;
91 }
92
Dump() const93 void Dump() const final
94 {
95 if (!IsEnable()) {
96 DumpLog::GetInstance().Print(0, "Set `persist.ace.memorymonitor.enabled = 1` to enable this feature");
97 return;
98 }
99 std::lock_guard<std::mutex> lock(mutex_);
100 std::string out = "total = " + std::to_string(total_) + ", count = " + std::to_string(count_);
101 DumpLog::GetInstance().Print(0, out);
102 for (auto&& [typeName, info] : typeMap_) {
103 if (info.total == 0) {
104 continue;
105 }
106 out = typeName + ": total = " + std::to_string(info.total) + ", count = " + std::to_string(info.count);
107 DumpLog::GetInstance().Print(1, out);
108 }
109 }
110
111 private:
112 struct MemInfo {
113 size_t size = 0;
114 std::string typeName = "Unknown";
115 };
116
117 struct TypeInfo {
118 size_t count = 0;
119 size_t total = 0;
120 };
121
122 std::map<void*, MemInfo> memoryMap_;
123 std::map<std::string, TypeInfo> typeMap_;
124 size_t total_ = 0;
125 size_t count_ = 0;
126
127 mutable std::mutex mutex_;
128 };
129
GetInstance()130 MemoryMonitor& MemoryMonitor::GetInstance()
131 {
132 static MemoryMonitorImpl instance;
133 return instance;
134 }
135
136 } // namespace OHOS::Ace
137