Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / xpcom / base / nsMemoryImpl.cpp
blob4996d27c7a131b993e1ecdec6808cab37a2b7e70
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsMemory.h"
8 #include "nsThreadUtils.h"
10 #include "nsIObserver.h"
11 #include "nsIObserverService.h"
12 #include "nsIRunnable.h"
13 #include "nsISimpleEnumerator.h"
15 #include "nsCOMPtr.h"
16 #include "mozilla/Services.h"
17 #include "mozilla/Atomics.h"
19 #ifdef ANDROID
20 # include <stdio.h>
22 // Minimum memory threshold for a device to be considered
23 // a low memory platform. This value has be in sync with
24 // Java's equivalent threshold, defined in HardwareUtils.java
25 # define LOW_MEMORY_THRESHOLD_KB (384 * 1024)
26 #endif
28 static mozilla::Atomic<bool> sIsFlushing;
29 static PRIntervalTime sLastFlushTime = 0;
31 // static
32 bool nsMemory::IsLowMemoryPlatform() {
33 #ifdef ANDROID
34 static int sLowMemory =
35 -1; // initialize to unknown, lazily evaluate to 0 or 1
36 if (sLowMemory == -1) {
37 sLowMemory = 0; // assume "not low memory" in case file operations fail
39 // check if MemTotal from /proc/meminfo is less than LOW_MEMORY_THRESHOLD_KB
40 FILE* fd = fopen("/proc/meminfo", "r");
41 if (!fd) {
42 return false;
44 uint64_t mem = 0;
45 int rv = fscanf(fd, "MemTotal: %" PRIu64 " kB", &mem);
46 if (fclose(fd)) {
47 return false;
49 if (rv != 1) {
50 return false;
52 sLowMemory = (mem < LOW_MEMORY_THRESHOLD_KB) ? 1 : 0;
54 return (sLowMemory == 1);
55 #else
56 return false;
57 #endif
60 static void RunFlushers(const char16_t* aReason) {
61 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
62 if (os) {
63 // Instead of:
64 // os->NotifyObservers(this, "memory-pressure", aReason);
65 // we are going to do this manually to see who/what is
66 // deallocating.
68 nsCOMPtr<nsISimpleEnumerator> e;
69 os->EnumerateObservers("memory-pressure", getter_AddRefs(e));
71 if (e) {
72 nsCOMPtr<nsIObserver> observer;
73 bool loop = true;
75 while (NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop) {
76 nsCOMPtr<nsISupports> supports;
77 e->GetNext(getter_AddRefs(supports));
79 if (!supports) {
80 continue;
83 observer = do_QueryInterface(supports);
84 observer->Observe(observer, "memory-pressure", aReason);
89 sIsFlushing = false;
92 static nsresult FlushMemory(const char16_t* aReason, bool aImmediate) {
93 if (aImmediate) {
94 // They've asked us to run the flusher *immediately*. We've
95 // got to be on the UI main thread for us to be able to do
96 // that...are we?
97 if (!NS_IsMainThread()) {
98 NS_ERROR("can't synchronously flush memory: not on UI thread");
99 return NS_ERROR_FAILURE;
103 bool lastVal = sIsFlushing.exchange(true);
104 if (lastVal) {
105 return NS_OK;
108 PRIntervalTime now = PR_IntervalNow();
110 // Run the flushers immediately if we can; otherwise, proxy to the
111 // UI thread and run 'em asynchronously.
112 nsresult rv = NS_OK;
113 if (aImmediate) {
114 RunFlushers(aReason);
115 } else {
116 // Don't broadcast more than once every 1000ms to avoid being noisy
117 if (PR_IntervalToMicroseconds(now - sLastFlushTime) > 1000) {
118 nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
119 "FlushMemory",
120 [reason = aReason]() -> void { RunFlushers(reason); }));
121 NS_DispatchToMainThread(runnable.forget());
125 sLastFlushTime = now;
126 return rv;
129 nsresult nsMemory::HeapMinimize(bool aImmediate) {
130 return FlushMemory(u"heap-minimize", aImmediate);