void MemoryPressureHandler::install()
{
    if (m_installed || m_holdOffTimer.isActive())
        return;

    if (!tryEnsureEventFD())
        return;

    m_eventFDPoller = std::make_unique<EventFDPoller>(m_eventFD.value(), [this] {
        // FIXME: Current memcg does not provide any way for users to know how serious the memory pressure is.
        // So we assume all notifications from memcg are critical for now. If memcg had better inferfaces
        // to get a detailed memory pressure level in the future, we should update here accordingly.
        bool critical = true;
        if (ReliefLogger::loggingEnabled())
            LOG(MemoryPressure, "Got memory pressure notification (%s)", critical ? "critical" : "non-critical");

        setUnderMemoryPressure(critical);
        if (isMainThread())
            respondToMemoryPressure(critical ? Critical::Yes : Critical::No);
        else
            RunLoop::main().dispatch([this, critical] { respondToMemoryPressure(critical ? Critical::Yes : Critical::No); });
    });

    if (ReliefLogger::loggingEnabled() && isUnderMemoryPressure())
        LOG(MemoryPressure, "System is no longer under memory pressure.");

    setUnderMemoryPressure(false);
    m_installed = true;
}
Esempio n. 2
0
void MemoryPressureHandler::releaseCriticalMemory(Synchronous synchronous)
{
    {
        ReliefLogger log("Empty the PageCache");
        // Right now, the only reason we call release critical memory while not under memory pressure is if the process is about to be suspended.
        PruningReason pruningReason = isUnderMemoryPressure() ? PruningReason::MemoryPressure : PruningReason::ProcessSuspended;
        PageCache::singleton().pruneToSizeNow(0, pruningReason);
    }

    {
        ReliefLogger log("Prune MemoryCache live resources");
        MemoryCache::singleton().pruneLiveResourcesToSize(0);
    }

    {
        ReliefLogger log("Drain CSSValuePool");
        CSSValuePool::singleton().drain();
    }

    {
        ReliefLogger log("Discard StyleResolvers");
        Vector<RefPtr<Document>> documents;
        copyToVector(Document::allDocuments(), documents);
        for (auto& document : documents)
            document->clearStyleResolver();
    }

    {
        ReliefLogger log("Discard all JIT-compiled code");
        GCController::singleton().deleteAllCode();
    }

    {
        ReliefLogger log("Invalidate font cache");
        FontCache::singleton().invalidate();
    }

#if ENABLE(VIDEO)
    {
        ReliefLogger log("Dropping buffered data from paused media elements");
        for (auto* mediaElement: HTMLMediaElement::allMediaElements()) {
            if (mediaElement->paused())
                mediaElement->purgeBufferedDataIfPossible();
        }
    }
#endif

    if (synchronous == Synchronous::Yes) {
        ReliefLogger log("Collecting JavaScript garbage");
        GCController::singleton().garbageCollectNow();
    } else
        GCController::singleton().garbageCollectNowIfNotDoneRecently();
}
void MemoryPressureHandler::releaseCriticalMemory(Synchronous synchronous)
{
    {
        ReliefLogger log("Empty the PageCache");
        // Right now, the only reason we call release critical memory while not under memory pressure is if the process is about to be suspended.
        PruningReason pruningReason = isUnderMemoryPressure() ? PruningReason::MemoryPressure : PruningReason::ProcessSuspended;
        PageCache::singleton().pruneToSizeNow(0, pruningReason);
    }

    {
        ReliefLogger log("Prune MemoryCache live resources");
        MemoryCache::singleton().pruneLiveResourcesToSize(0, /*shouldDestroyDecodedDataForAllLiveResources*/ true);
    }

    {
        ReliefLogger log("Drain CSSValuePool");
        CSSValuePool::singleton().drain();
    }

    {
        ReliefLogger log("Discard StyleResolvers");
        Vector<RefPtr<Document>> documents;
        copyToVector(Document::allDocuments(), documents);
        for (auto& document : documents)
            document->clearStyleResolver();
    }

    {
        ReliefLogger log("Discard all JIT-compiled code");
        GCController::singleton().deleteAllCode();
    }

#if ENABLE(VIDEO)
    {
        ReliefLogger log("Dropping buffered data from paused media elements");
        for (auto* mediaElement: HTMLMediaElement::allMediaElements()) {
            if (mediaElement->paused())
                mediaElement->purgeBufferedDataIfPossible();
        }
    }
#endif

    if (synchronous == Synchronous::Yes) {
        ReliefLogger log("Collecting JavaScript garbage");
        GCController::singleton().garbageCollectNow();
    } else
        GCController::singleton().garbageCollectNowIfNotDoneRecently();

    // We reduce tiling coverage while under memory pressure, so make sure to drop excess tiles ASAP.
    Page::forEachPage([](Page& page) {
        page.chrome().client().scheduleCompositingLayerFlush();
    });
}
void MemoryPressureHandler::install()
{
    if (m_installed)
        return;

    m_eventFD = eventfd(0, EFD_CLOEXEC);
    if (m_eventFD == -1) {
        LOG(MemoryPressure, "eventfd() failed: %m");
        return;
    }

    m_pressureLevelFD = open(s_cgroupMemoryPressureLevel, O_CLOEXEC | O_RDONLY);
    if (m_pressureLevelFD == -1) {
        logErrorAndCloseFDs("Failed to open memory.pressure_level");
        return;
    }

    int fd = open(s_cgroupEventControl, O_CLOEXEC | O_WRONLY);
    if (fd == -1) {
        logErrorAndCloseFDs("Failed to open cgroup.event_control");
        return;
    }

    char line[128] = {0, };
    if (snprintf(line, sizeof(line), "%d %d low", m_eventFD, m_pressureLevelFD) < 0
        || write(fd, line, strlen(line) + 1) < 0) {
        logErrorAndCloseFDs("Failed to write cgroup.event_control");
        close(fd);
        return;
    }
    close(fd);

    m_threadID = createThread(waitForMemoryPressureEvent, this, "WebCore: MemoryPressureHandler");
    if (!m_threadID) {
        logErrorAndCloseFDs("Failed to create a thread for MemoryPressureHandler");
        return;
    }

    if (ReliefLogger::loggingEnabled() && isUnderMemoryPressure())
        LOG(MemoryPressure, "System is no longer under memory pressure.");

    setUnderMemoryPressure(false);
    m_installed = true;
}