Поиск использования памяти в Java - PullRequest
6 голосов
/ 17 февраля 2009

Ниже приведен сценарий, который мне нужно решить. Я столкнулся с двумя решениями.

Мне нужно поддерживать кеш данных, извлекаемых из базы данных, для отображения в графическом интерфейсе Swing. Всякий раз, когда моя память JVM превышает 70% выделенной памяти, я должен предупредить пользователя о чрезмерном использовании. И как только использование памяти JVM превысит 80%, мне придется прекратить все запросы к базе данных и очистить существующий кеш, извлеченный как часть пользовательских операций и уведомив пользователя. В процессе очистки я буду вручную обрабатывать удаление некоторых данных на основе некоторых правил и инструктирую JVM для GC. Всякий раз, когда происходит GC, если память очищается и достигает 60% выделенной памяти, мне нужно перезапустить всю обработку базы данных и вернуть контроль пользователю.

Для проверки статистики памяти JVM я нашел следующие два решения. Не смог решить, какой путь лучше и почему.

  1. Runtime.freeMemory () - поток, созданный для запуска каждые 10 секунд и проверки наличия свободной памяти, и, если объем памяти превышает указанные выше ограничения, необходимые всплывающие окна сообщат пользователю и вызовут методы для остановки операций и освобождения память.

  2. MemoryPoolMXBean.getUsage () - Java 5 представила JMX для получения снимка памяти во время выполнения. В JMX я не могу использовать пороговое уведомление, поскольку оно будет уведомлять, только когда память достигнет / превысит заданный порог. Единственный способ использовать опрос в MemoryMXBean и проверять статистику памяти за период.

В случае использования опроса, мне кажется, что обе реализации будут одинаковыми.

Пожалуйста, предложите преимущества методов и, если есть какие-либо другие альтернативы / какие-либо исправления к методам, использующим методы.

Ответы [ 8 ]

14 голосов
/ 17 февраля 2009

Примечание: Runtime.freeMemory() не указывает объем памяти, который остается для выделения, это просто объем памяти, который свободен в текущей выделенной памяти (который изначально меньше максимального объема памяти, настроенного виртуальной машиной). использовать), но со временем растет.

При запуске виртуальной машины максимальный объем памяти (Runtime.maxMemory()) просто определяет верхний предел памяти, который может выделить виртуальная машина (настраивается с помощью опции -Xmx VM). Общий объем памяти (Runtime.totalMemory()) - это начальный размер памяти, выделенной для процесса VM (настраивается с помощью параметра VM -Xms), и он будет динамически увеличиваться каждый раз, когда вы выделяете больше, чем свободная в настоящее время часть (Runtime.freeMemory() ), пока не достигнет максимальной памяти.

Интересующая вас метрика - это память, доступная для дальнейшего распределения:

long usableFreeMemory= Runtime.getRuntime().maxMemory()
    -Runtime.getRuntime().totalMemory()
    +Runtime.getRuntime().freeMemory()

или

double usedPercent=(double)(Runtime.getRuntime().totalMemory()
    -Runtime.getRuntime().freeMemory())/Runtime.getRuntime().maxMemory()
7 голосов
/ 18 февраля 2009

Обычный способ справиться с подобными вещами - использовать WeakReference с и SoftReference с. Вам нужно использовать и то и другое: слабая ссылка означает, что у вас нет нескольких копий вещей, а мягкие ссылки означают, что GC будет зависать на вещах, пока не начнет исчерпываться память.

Если вам нужно выполнить дополнительную очистку, вы можете добавить ссылки на очереди и переопределить методы уведомления очереди, чтобы запустить очистку. Это все весело, но вы должны понимать, что делают эти классы.

5 голосов
/ 17 февраля 2009

Вполне нормально, что JVM использует до 100% памяти, и они возвращаются к 10% после GC и делают это каждые несколько секунд.

Вам не нужно пытаться управлять памятью таким образом. Вы не можете сказать, сколько памяти сохраняется, пока не будет запущен полный сборщик мусора.

Я предлагаю вам разобраться, чего вы действительно пытаетесь достичь, и посмотреть на проблему по-другому.

4 голосов
/ 17 февраля 2009

Указанные вами требования явно противоречат принципам работы сборки мусора в JVM.

из-за поведения JVM будет очень сложно правильно предупредить пользователей. В целом прекращение работы с базами данных, очистка и повторный запуск на самом деле - не самый лучший способ.

Позвольте JVM делать то, что он должен делать, обрабатывать всю память, связанную с вами. Современные поколения JVM очень хороши в этом, и с некоторой тонкой настройкой параметров GC вы получите намного более чистую обработку памяти, чем сами все заставляете

В статьях типа http://www.kodewerk.com/advice_on_jvm_heap_tuning_dont_touch_that_dial.htm упоминаются плюсы и минусы и дается хорошее объяснение того, что виртуальная машина делает для вас

2 голосов
/ 17 февраля 2009

Я использовал только первый метод для аналогичной задачи, и он был в порядке.

Одна вещь, которую вы должны заметить, для обоих методов - это реализовать какой-то способ устранения неполадок - то есть, как только вы узнаете, что достигли 70% памяти, подождите минуту (или любое другое время, которое вы считаете подходящим) - GC запустить в это время и очистить много памяти.

Если вы внедрите в свою систему график Runtime.freeMemory (), вы увидите, как память постоянно увеличивается и уменьшается, увеличивается и уменьшается.

1 голос
/ 09 декабря 2009

VisualVM немного лучше, чем JConsole, потому что он дает вам хорошее визуальное представление сборщика мусора.

0 голосов
/ 15 сентября 2011

Очень поздно после оригинального поста, я знаю, но я думал, что выложу пример того, как я это сделал. Надеюсь, это кому-нибудь пригодится (подчеркиваю, это доказательство принципиального примера, ничего более ... тоже не особо элегантно :))

Просто вставьте эти две функции в класс, и он должен работать.

РЕДАКТИРОВАТЬ: О, и import java.util.ArrayList; import java.util.List;

public static int MEM(){
    return (int)(Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory() +Runtime.getRuntime().freeMemory())/1024/1024;
}

public static void main(String[] args) throws InterruptedException
{
    List list = new ArrayList();

    //get available memory before filling list
    int initMem = MEM();
    int lowMemWarning = (int) (initMem * 0.2);
    int highMem = (int) (initMem *0.8);


    int iteration =0;
    while(true)
    {
        //use up some memory
        list.add(Math.random());

        //report
        if(++iteration%10000==0)
        {
            System.out.printf("Available Memory: %dMb \tListSize: %d\n", MEM(),list.size());

            //if low on memory, clear list and await garbage collection before continuing
            if(MEM()<lowMemWarning)
            {
                System.out.printf("Warning! Low memory (%dMb remaining). Clearing list and cleaning up.\n",MEM());

                //clear list
                list = new ArrayList();  //obviously, here is a good place to put your warning logic

                //ensure garbage collection occurs before continuing to re-add to list, to avoid immediately entering this block again
                while(MEM()<highMem)
                {
                    System.out.printf("Awaiting gc...(%dMb remaining)\n",MEM());
                    //give it a nudge
                    Runtime.getRuntime().gc(); 
                    Thread.sleep(250);
                }

                System.out.printf("gc successful! Continuing to fill list (%dMb remaining). List size: %d\n",MEM(),list.size());
                Thread.sleep(3000); //just to view output
            }
        }
    }
}

РЕДАКТИРОВАТЬ: Этот подход все еще основывается на разумной настройке памяти в jvm с использованием -Xmx, однако.

EDIT2: Кажется, что строка запроса gc действительно помогает, по крайней мере, на моем jvm. YMMV.

0 голосов
/ 18 февраля 2009

Посмотрите в JConsole. Он отображает необходимую вам информацию, поэтому необходимо адаптировать ее к вашим потребностям (учитывая, что вы используете Sun Java 6).

Это также позволяет вам отделить процесс съемки от того, на что вы хотите посмотреть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...