1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/base/nsMemoryImpl.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,218 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsMemoryImpl.h" 1.10 +#include "nsThreadUtils.h" 1.11 + 1.12 +#include "nsIObserver.h" 1.13 +#include "nsIObserverService.h" 1.14 +#include "nsISimpleEnumerator.h" 1.15 + 1.16 +#include "nsCOMPtr.h" 1.17 +#include "mozilla/Services.h" 1.18 + 1.19 +#ifdef ANDROID 1.20 +#include <stdio.h> 1.21 + 1.22 +// Minimum memory threshold for a device to be considered 1.23 +// a low memory platform. This value has be in sync with 1.24 +// Java's equivalent threshold, defined in 1.25 +// mobile/android/base/util/HardwareUtils.java 1.26 +#define LOW_MEMORY_THRESHOLD_KB (384 * 1024) 1.27 +#endif 1.28 + 1.29 +static nsMemoryImpl sGlobalMemory; 1.30 + 1.31 +NS_IMPL_QUERY_INTERFACE(nsMemoryImpl, nsIMemory) 1.32 + 1.33 +NS_IMETHODIMP_(void*) 1.34 +nsMemoryImpl::Alloc(size_t size) 1.35 +{ 1.36 + return NS_Alloc(size); 1.37 +} 1.38 + 1.39 +NS_IMETHODIMP_(void*) 1.40 +nsMemoryImpl::Realloc(void* ptr, size_t size) 1.41 +{ 1.42 + return NS_Realloc(ptr, size); 1.43 +} 1.44 + 1.45 +NS_IMETHODIMP_(void) 1.46 +nsMemoryImpl::Free(void* ptr) 1.47 +{ 1.48 + NS_Free(ptr); 1.49 +} 1.50 + 1.51 +NS_IMETHODIMP 1.52 +nsMemoryImpl::HeapMinimize(bool aImmediate) 1.53 +{ 1.54 + return FlushMemory(MOZ_UTF16("heap-minimize"), aImmediate); 1.55 +} 1.56 + 1.57 +NS_IMETHODIMP 1.58 +nsMemoryImpl::IsLowMemory(bool *result) 1.59 +{ 1.60 + NS_ERROR("IsLowMemory is deprecated. See bug 592308."); 1.61 + *result = false; 1.62 + return NS_OK; 1.63 +} 1.64 + 1.65 +NS_IMETHODIMP 1.66 +nsMemoryImpl::IsLowMemoryPlatform(bool *result) 1.67 +{ 1.68 +#ifdef ANDROID 1.69 + static int sLowMemory = -1; // initialize to unknown, lazily evaluate to 0 or 1 1.70 + if (sLowMemory == -1) { 1.71 + sLowMemory = 0; // assume "not low memory" in case file operations fail 1.72 + *result = false; 1.73 + 1.74 + // check if MemTotal from /proc/meminfo is less than LOW_MEMORY_THRESHOLD_KB 1.75 + FILE* fd = fopen("/proc/meminfo", "r"); 1.76 + if (!fd) { 1.77 + return NS_OK; 1.78 + } 1.79 + uint64_t mem = 0; 1.80 + int rv = fscanf(fd, "MemTotal: %llu kB", &mem); 1.81 + if (fclose(fd)) { 1.82 + return NS_OK; 1.83 + } 1.84 + if (rv != 1) { 1.85 + return NS_OK; 1.86 + } 1.87 + sLowMemory = (mem < LOW_MEMORY_THRESHOLD_KB) ? 1 : 0; 1.88 + } 1.89 + *result = (sLowMemory == 1); 1.90 +#else 1.91 + *result = false; 1.92 +#endif 1.93 + return NS_OK; 1.94 +} 1.95 + 1.96 +/*static*/ nsresult 1.97 +nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void **aResult) 1.98 +{ 1.99 + if (NS_WARN_IF(outer)) 1.100 + return NS_ERROR_NO_AGGREGATION; 1.101 + return sGlobalMemory.QueryInterface(aIID, aResult); 1.102 +} 1.103 + 1.104 +nsresult 1.105 +nsMemoryImpl::FlushMemory(const char16_t* aReason, bool aImmediate) 1.106 +{ 1.107 + nsresult rv = NS_OK; 1.108 + 1.109 + if (aImmediate) { 1.110 + // They've asked us to run the flusher *immediately*. We've 1.111 + // got to be on the UI main thread for us to be able to do 1.112 + // that...are we? 1.113 + if (!NS_IsMainThread()) { 1.114 + NS_ERROR("can't synchronously flush memory: not on UI thread"); 1.115 + return NS_ERROR_FAILURE; 1.116 + } 1.117 + } 1.118 + 1.119 + bool lastVal = sIsFlushing.exchange(true); 1.120 + if (lastVal) 1.121 + return NS_OK; 1.122 + 1.123 + PRIntervalTime now = PR_IntervalNow(); 1.124 + 1.125 + // Run the flushers immediately if we can; otherwise, proxy to the 1.126 + // UI thread an run 'em asynchronously. 1.127 + if (aImmediate) { 1.128 + rv = RunFlushers(aReason); 1.129 + } 1.130 + else { 1.131 + // Don't broadcast more than once every 1000ms to avoid being noisy 1.132 + if (PR_IntervalToMicroseconds(now - sLastFlushTime) > 1000) { 1.133 + sFlushEvent.mReason = aReason; 1.134 + rv = NS_DispatchToMainThread(&sFlushEvent, NS_DISPATCH_NORMAL); 1.135 + } 1.136 + } 1.137 + 1.138 + sLastFlushTime = now; 1.139 + return rv; 1.140 +} 1.141 + 1.142 +nsresult 1.143 +nsMemoryImpl::RunFlushers(const char16_t* aReason) 1.144 +{ 1.145 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.146 + if (os) { 1.147 + 1.148 + // Instead of: 1.149 + // os->NotifyObservers(this, "memory-pressure", aReason); 1.150 + // we are going to do this manually to see who/what is 1.151 + // deallocating. 1.152 + 1.153 + nsCOMPtr<nsISimpleEnumerator> e; 1.154 + os->EnumerateObservers("memory-pressure", getter_AddRefs(e)); 1.155 + 1.156 + if ( e ) { 1.157 + nsCOMPtr<nsIObserver> observer; 1.158 + bool loop = true; 1.159 + 1.160 + while (NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop) 1.161 + { 1.162 + nsCOMPtr<nsISupports> supports; 1.163 + e->GetNext(getter_AddRefs(supports)); 1.164 + 1.165 + if (!supports) 1.166 + continue; 1.167 + 1.168 + observer = do_QueryInterface(supports); 1.169 + observer->Observe(observer, "memory-pressure", aReason); 1.170 + } 1.171 + } 1.172 + } 1.173 + 1.174 + sIsFlushing = false; 1.175 + return NS_OK; 1.176 +} 1.177 + 1.178 +// XXX need NS_IMPL_STATIC_ADDREF/RELEASE 1.179 +NS_IMETHODIMP_(MozExternalRefCountType) nsMemoryImpl::FlushEvent::AddRef() { return 2; } 1.180 +NS_IMETHODIMP_(MozExternalRefCountType) nsMemoryImpl::FlushEvent::Release() { return 1; } 1.181 +NS_IMPL_QUERY_INTERFACE(nsMemoryImpl::FlushEvent, nsIRunnable) 1.182 + 1.183 +NS_IMETHODIMP 1.184 +nsMemoryImpl::FlushEvent::Run() 1.185 +{ 1.186 + sGlobalMemory.RunFlushers(mReason); 1.187 + return NS_OK; 1.188 +} 1.189 + 1.190 +mozilla::Atomic<bool> 1.191 +nsMemoryImpl::sIsFlushing; 1.192 + 1.193 +PRIntervalTime 1.194 +nsMemoryImpl::sLastFlushTime = 0; 1.195 + 1.196 +nsMemoryImpl::FlushEvent 1.197 +nsMemoryImpl::sFlushEvent; 1.198 + 1.199 +XPCOM_API(void*) 1.200 +NS_Alloc(size_t size) 1.201 +{ 1.202 + return moz_xmalloc(size); 1.203 +} 1.204 + 1.205 +XPCOM_API(void*) 1.206 +NS_Realloc(void* ptr, size_t size) 1.207 +{ 1.208 + return moz_xrealloc(ptr, size); 1.209 +} 1.210 + 1.211 +XPCOM_API(void) 1.212 +NS_Free(void* ptr) 1.213 +{ 1.214 + moz_free(ptr); 1.215 +} 1.216 + 1.217 +nsresult 1.218 +NS_GetMemoryManager(nsIMemory* *result) 1.219 +{ 1.220 + return sGlobalMemory.QueryInterface(NS_GET_IID(nsIMemory), (void**) result); 1.221 +}