Commit 6bc1e340 authored by Doug Thayer's avatar Doug Thayer
Browse files

Bug 1651941 - Free unreferenced StartupCache entries on write r=froydnj

On first run, when the cache is empty, we collect a lot of freshly allocated
buffers for StartupCache entries. These entries are generally not requested
again after being put in the StartupCache, so they are generally safe to free
(as ownership of them was given to us by contract in PutBuffer.) This tends
to free up >10MB.

Differential Revision: https://phabricator.services.mozilla.com/D83399
parent c4dd1705
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include "prio.h"
#include "PLDHashTable.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/AutoMemMap.h"
#include "mozilla/IOBuffers.h"
#include "mozilla/ipc/FileDescriptor.h"
@@ -889,6 +890,12 @@ nsresult StartupCache::GetBuffer(const char* id, const char** outbuf,
  *outbuf = value.mData.get();
  *length = value.mUncompressedSize;

  if (value.mData.IsOwned()) {
    // We're returning a raw reference to this entry's owned buffer, so we can
    // no longer free that buffer.
    value.mFlags += StartupCacheEntryFlags::DoNotFree;
  }

  return NS_OK;
}

@@ -1146,6 +1153,21 @@ Result<Ok, nsresult> StartupCache::WriteToDisk() {
  mCacheData.reset();
  tmpFile->MoveToNative(nullptr, leafName);

  // If we're shutting down, we do not care about freeing up memory right now.
  if (AppShutdown::IsShuttingDown()) {
    return Ok();
  }

  // We've just written our buffers to disk, and we're 60 seconds out from
  // startup, so they're unlikely to be needed again any time soon; let's
  // clean up what we can.
  for (auto iter = mTable.iter(); !iter.done(); iter.next()) {
    auto& value = iter.get().value();
    if (!value.mFlags.contains(StartupCacheEntryFlags::DoNotFree)) {
      value.mData = nullptr;
    }
  }

  return Ok();
}

+12 −1
Original line number Diff line number Diff line
@@ -125,10 +125,11 @@ static const int kStartupCacheKeyLengthCap = 1024;
// for relatively uncertain performance gains. For the time being, we just
// keep the existing model unchanged.
class MaybeOwnedCharPtr {
 public:
 private:
  char* mPtr;
  bool mOwned;

 public:
  ~MaybeOwnedCharPtr() {
    if (mOwned) {
      delete[] mPtr;
@@ -149,6 +150,9 @@ class MaybeOwnedCharPtr {
  }

  MaybeOwnedCharPtr& operator=(decltype(nullptr)) {
    if (mOwned) {
      delete[] mPtr;
    }
    mPtr = nullptr;
    mOwned = false;
    return *this;
@@ -160,6 +164,8 @@ class MaybeOwnedCharPtr {

  char* get() const { return mPtr; }

  bool IsOwned() const { return mOwned; }

  explicit MaybeOwnedCharPtr(char* aBytes) : mPtr(aBytes), mOwned(false) {}

  explicit MaybeOwnedCharPtr(UniquePtr<char[]>&& aBytes)
@@ -191,6 +197,11 @@ enum class StartupCacheEntryFlags {
  Shared,
  RequestedByChild,
  AddedThisSession,

  // We want to track whether code outside the StartupCache has requested
  // and gotten access to a pointer to this item's underlying buffer, and
  // this flag is the mechanism for doing that.
  DoNotFree,
};

struct StartupCacheEntry {