Index: base/process/process_metrics_win.cc |
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc |
index fe4b84988f1a2736da6fef1b9a3c5ca0552f5ba0..5b2777bb364bfa1c53679432fd511acfb8dbd4a4 100644 |
--- a/base/process/process_metrics_win.cc |
+++ b/base/process/process_metrics_win.cc |
@@ -14,6 +14,7 @@ |
#include "base/logging.h" |
#include "base/memory/ptr_util.h" |
+#include "base/process/memory.h" |
#include "base/sys_info.h" |
namespace base { |
@@ -140,6 +141,36 @@ void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const { |
usage->priv = committed_private / 1024; |
} |
+namespace { |
+ |
+class WorkingSetInformationBuffer { |
+ public: |
+ WorkingSetInformationBuffer() {} |
+ ~WorkingSetInformationBuffer() { Clear(); } |
+ |
+ bool Reserve(size_t size) { |
+ Clear(); |
+ // Use UncheckedMalloc here because this can be called from the code |
+ // that handles low memory condition. |
+ return UncheckedMalloc(size, reinterpret_cast<void**>(&buffer_)); |
+ } |
+ |
+ PSAPI_WORKING_SET_INFORMATION* get() { return buffer_; } |
+ const PSAPI_WORKING_SET_INFORMATION* operator ->() const { return buffer_; } |
+ |
+ private: |
+ void Clear() { |
+ free(buffer_); |
+ buffer_ = nullptr; |
+ } |
+ |
+ PSAPI_WORKING_SET_INFORMATION* buffer_ = nullptr; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(WorkingSetInformationBuffer); |
+}; |
+ |
+} // namespace |
+ |
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
size_t ws_private = 0; |
size_t ws_shareable = 0; |
@@ -149,40 +180,33 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
memset(ws_usage, 0, sizeof(*ws_usage)); |
DWORD number_of_entries = 4096; // Just a guess. |
- PSAPI_WORKING_SET_INFORMATION* buffer = NULL; |
+ WorkingSetInformationBuffer buffer; |
int retries = 5; |
for (;;) { |
DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) + |
(number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); |
- // if we can't expand the buffer, don't leak the previous |
- // contents or pass a NULL pointer to QueryWorkingSet |
- PSAPI_WORKING_SET_INFORMATION* new_buffer = |
- reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>( |
- realloc(buffer, buffer_size)); |
- if (!new_buffer) { |
- free(buffer); |
+ if (!buffer.Reserve(buffer_size)) |
return false; |
- } |
- buffer = new_buffer; |
// Call the function once to get number of items |
- if (QueryWorkingSet(process_, buffer, buffer_size)) |
+ if (QueryWorkingSet(process_, buffer.get(), buffer_size)) |
break; // Success |
- if (GetLastError() != ERROR_BAD_LENGTH) { |
- free(buffer); |
+ if (GetLastError() != ERROR_BAD_LENGTH) |
return false; |
- } |
number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries); |
// Maybe some entries are being added right now. Increase the buffer to |
- // take that into account. |
- number_of_entries = static_cast<DWORD>(number_of_entries * 1.25); |
+ // take that into account. Increasing by 10% should generally be enough, |
+ // especially considering the potentially low memory condition during the |
+ // call (when called from OomMemoryDetails) and the potentially high |
+ // number of entries (300K was observed in crash dumps). |
+ number_of_entries = static_cast<DWORD>(number_of_entries * 1.1); |
if (--retries == 0) { |
- free(buffer); // If we're looping, eventually fail. |
+ // If we're looping, eventually fail. |
return false; |
} |
} |
@@ -205,7 +229,6 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { |
ws_usage->priv = ws_private * PAGESIZE_KB; |
ws_usage->shareable = ws_shareable * PAGESIZE_KB; |
ws_usage->shared = ws_shared * PAGESIZE_KB; |
- free(buffer); |
return true; |
} |