Java использует слишком много памяти

мой Java записанное приложение использует слишком много памяти.

Как действительно программирует работу: Пользователь выбирает дату из календаря (GUI) и данные загрузок приложения в компонент JTable. Каждый раз данные загружаются, новый TableModel создается и устанавливается. Никакой новый JTable не создается, просто модель.

В чем проблема?: каждый новый дневной выбор от календаря и загружающийся к JTable использует приблизительно 2-3 МБ памяти. На запуске приложение использует cca 50-60 МБ RAM, после того, как немного "щелчков" по календарю (как 20), приложение использует полный Размер "кучи" (128 МБ). Сбои приложения, конечно...

Что я должен сделать?: Я - вполне уверенные запросы базы данных, в порядке. Я мог бы так или иначе установить больший размер "кучи" (я погуглил, но это будет только решением для моего компьютера, пользовательская привычка делают это), ИЛИ я должен так или иначе удалить старый TableModel с данными DB. Но разве это не должно быть работой Сборщика "мусора"? Я в состоянии вызвать его (System.gc ()), но это не помогает...

Спасибо за любой совет!

РЕДАКТИРОВАНИЕ: Код для Обработки событий календаря (я удалил Javadoc, это находится на моем родном языке),

package timesheet.handlers;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import org.jdesktop.swingx.JXMonthView;
import org.jdesktop.swingx.event.DateSelectionEvent;
import org.jdesktop.swingx.event.DateSelectionListener;
import timesheet.database.WorkerOperations;
import timesheet.frames.WorkerFrame;
import timesheet.logictrier.*;


public class WorkerMonthViewHandler {
    private JXMonthView monthView;
    private WorkerFrame workerFrame;
    private WorkerOperations wops;
    private Date[] week = new Date[5];
    private WorkerTasksTableHandler wtth;

    public WorkerMonthViewHandler(WorkerFrame workerFrame) {
        this.workerFrame = workerFrame;
        this.monthView = workerFrame.getWorkerMonthView();
        wops = workerFrame.getWorkerOperations(); // for DB usage
    }

    public void initMonthView() {
        List<Task> tasks = wops.getWorkerTasks(workerFrame.getWorker()); // db select
        for (Task task : tasks) {
            if (!monthView.getSelection().contains(task.getPlannedStart())) { 
                monthView.addFlaggedDates(task.getPlannedStart());
                monthView.addFlaggedDates(task.gePlannedEnd()); // not really important
            }
        }
        monthView.setSelectionDate(new Date());
        monthView.getSelectionModel().addDateSelectionListener(new DateSelectionListener() {
            public void valueChanged(DateSelectionEvent dse) {
                Date d = monthView.getSelectionDate();
                for (int i=0; i<week.length; i++) {
                    if (d.equals(week[i])) {     
                        return;
                    }
                }
                Calendar cal = new GregorianCalendar();
                cal.setTime(d);
                long dayMs = 24 * 60 * 60 * 1000;
                switch (cal.get(Calendar.DAY_OF_WEEK)) {
                    case(Calendar.MONDAY) : {
                        week[0] = new Date(cal.getTimeInMillis());
                        week[1] = new Date(cal.getTimeInMillis()+dayMs);
                        week[2] = new Date(cal.getTimeInMillis()+2*dayMs);
                        week[3] = new Date(cal.getTimeInMillis()+3*dayMs);
                        week[4] = new Date(cal.getTimeInMillis()+4*dayMs);
                    } break;
                    case (Calendar.TUESDAY) : {
                        week[0] = new Date(cal.getTimeInMillis()-dayMs);
                        week[1] = new Date(cal.getTimeInMillis());
                        week[2] = new Date(cal.getTimeInMillis()+1*dayMs);
                        week[3] = new Date(cal.getTimeInMillis()+2*dayMs);
                        week[4] = new Date(cal.getTimeInMillis()+3*dayMs);
                    } break;
                    case (Calendar.WEDNESDAY) : {
                        week[0] = new Date(cal.getTimeInMillis()-2*dayMs);
                        week[1] = new Date(cal.getTimeInMillis()-dayMs);
                        week[2] = new Date(cal.getTimeInMillis());
                        week[3] = new Date(cal.getTimeInMillis()+1*dayMs);
                        week[4] = new Date(cal.getTimeInMillis()+2*dayMs);
                    } break;
                    case (Calendar.THURSDAY) : {
                        week[0] = new Date(cal.getTimeInMillis()-3*dayMs);
                        week[1] = new Date(cal.getTimeInMillis()-2*dayMs);
                        week[2] = new Date(cal.getTimeInMillis()-1*dayMs);
                        week[3] = new Date(cal.getTimeInMillis());
                        week[4] = new Date(cal.getTimeInMillis()+1*dayMs);
                    } break;
                    case (Calendar.FRIDAY) : {
                        week[0] = new Date(cal.getTimeInMillis()-4*dayMs);
                        week[1] = new Date(cal.getTimeInMillis()-3*dayMs);
                        week[2] = new Date(cal.getTimeInMillis()-2*dayMs);
                        week[3] = new Date(cal.getTimeInMillis()-dayMs);
                        week[4] = new Date(cal.getTimeInMillis());
                    } break;
                    case (Calendar.SATURDAY) : {
                        week[0] = new Date(cal.getTimeInMillis()-5*dayMs);
                        week[1] = new Date(cal.getTimeInMillis()-4*dayMs);
                        week[2] = new Date(cal.getTimeInMillis()-3*dayMs);
                        week[3] = new Date(cal.getTimeInMillis()-2*dayMs);
                        week[4] = new Date(cal.getTimeInMillis()-dayMs);
                    } break;
                    case (Calendar.SUNDAY) : {
                        week[0] = new Date(cal.getTimeInMillis()-6*dayMs);
                        week[1] = new Date(cal.getTimeInMillis()-5*dayMs);
                        week[2] = new Date(cal.getTimeInMillis()-4*dayMs);
                        week[3] = new Date(cal.getTimeInMillis()-3*dayMs);
                        week[4] = new Date(cal.getTimeInMillis()-2*dayMs);
                    } break;
                }
                wtth = new WorkerTasksTableHandler(workerFrame,week);
                wtth.createTable(); // sets model on JTable
            }
        });
    }

    public void reportTask() {
        wtth.reportTasks(); // simple DB insert
    }
}

Используя профилировщика NetBeans: Дата взята: Sun 28 февраля Файл 14:25:16 CET 2010 года: C:...\private\profiler\java_pid4708.hprof Размер файла: 72,2 МБ

Total bytes: 62 323 264
Total classes: 3 304
Total instances: 1 344 586
Classloaders: 18
GC roots: 2 860
Number of objects pending for finalization: 0
12
задан Miso 28 February 2010 в 13:29
поделиться

8 ответов

Вы запускали профилировщик вроде YourKit против этого? Я подозреваю, что это покажет некоторую утечку памяти из-за удерживаемых ссылок, когда они должны быть освобождены.Обратите внимание, что System.gc () является подсказкой JVM и не вызывает цикл GC.

В качестве альтернативы вашему приложению может просто потребоваться больше памяти, чем разрешено JVM выделить. JVM будет выделять только до максимума по умолчанию (в зависимости от вашей платформы). Попробуйте увеличить это значение с помощью:

java -Xmx256m {classname}

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

8
ответ дан 2 December 2019 в 22:05
поделиться

Это полностью похоже на утечку памяти из ваших компонентов Swing. Есть какой-то компонент, который создается несколько раз и прикрепляется к чему-то еще (обычно в качестве слушателя), поэтому его нельзя собрать мусором, поскольку на него все еще существует действительная ссылка. Как указал кто-то другой, любой профилировщик поможет вам найти источник.

Сделайте снимок кучи в начале приложения. Затем после того, как вы нажмете кнопку примерно десять раз, сделайте еще один снимок кучи и выполните сравнение. Должен быть набор объектов, которых, как вы знаете, не должно быть в памяти, но они есть. Затем вы можете узнать, что содержит ссылку на него, и исправить это.

0
ответ дан 2 December 2019 в 22:05
поделиться

Трудно сказать по коду, но есть ли вероятность, что вы постоянно добавляете FlaggedDates?

public void initMonthView() {
    List<Task> tasks = wops.getWorkerTasks(workerFrame.getWorker()); // db select
    for (Task task : tasks) {
        if (!monthView.getSelection().contains(task.getPlannedStart())) { 
            monthView.addFlaggedDates(task.getPlannedStart());
            monthView.addFlaggedDates(task.gePlannedEnd()); // not really important
        }
    }
0
ответ дан 2 December 2019 в 22:05
поделиться

Вам не нужны даты с точностью до миллисекунды каждый раз. Мне кажется, достаточно одного дня недели.

Лично я бы нашел способ предварительно заполнить этот календарь и кэшировать его. Не нужно каждый раз создавать заново. Стоит попробовать. Если вы повторно используете его каждый день, зачем заново создавать его каждый раз? Заполняйте его таймером каждый день в полночь. Сделайте его доступным только для чтения и разрешите всем пользователям делиться им.

Также не нужно каждый раз «новый» Календарь. Я бы сделал это так:

Calendar cal = Calendar.getInstance();

Пусть завод раздаст это.

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

ОБНОВЛЕНИЕ: Возможно этот поможет вам найти утечку памяти. По крайней мере, это контрольный список с того, с чего начать поиск.

0
ответ дан 2 December 2019 в 22:05
поделиться

Очевидно, какое-то количество объектов создается для каждого «щелчка» по календарю. Эти объекты не собираются сборщиком мусора, поэтому увеличивается использование памяти и возможная авария. Без фактического запуска кода, глядя на ваш образец кода, я бы сказал, что вероятным виновником является анонимный внутренний класс, созданный здесь:

monthView.getSelectionModel().addDateSelectionListener(new DateSelectionListener() {
  ...
}

Новый DateSelectionListener, который вы создаете, будет иметь ссылку на него (WorkerMonthViewHandler), я не могу посмотрите, как именно это вызовет проблему, не зная больше о том, как используется initMonthView, но я обнаружил, что рефакторинг анонимных внутренних классов, созданных в качестве слушателей на объектах Swing, помог выявить и, в конечном итоге, решить ряд утечек памяти в прошлом. Слушатели будут существовать до тех пор, пока существует объект Swing, который они слушают, поэтому они останутся без дела даже после того, как вы создадите новый WorkerMonthViewHandler, если исходный JTable Swing останется прежним.

Если вы хотите получить дополнительную информацию по этому поводу, попробуйте это, http://www.javalobby.org/java/forums/t19468.html .

Надеюсь, это поможет.

2
ответ дан 2 December 2019 в 22:05
поделиться

Джентельмены, спасибо всем за ответы. Я ценю каждый ответ .

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

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

        wtth = new WorkerTasksTableHandler(workerFrame,week);
        wtth.createTable(); // sets model on JTable

Результат: каждый раз, когда NEW TableModel создается со своим собственным Listener, как некоторые из вас заметили. {{1 }} Теперь я только перезагружаю данные (а не всю модель) и использую оригинальный Listener.

Взгляните на картинку, теперь она потребляет намного меньше ОЗУ, и сборщик мусора действительно работает :) alt text

-1
ответ дан 2 December 2019 в 22:05
поделиться

Прочитайте замечательную статью Вейко Крунича Как исправить утечки памяти в Java. Он предлагает диагностический путь для подобных проблем.

2
ответ дан 2 December 2019 в 22:05
поделиться

Здесь дикая догадка, но, как я часто вижу в C #, содержат ли ваши обработчики событий календаря / элементов управления ссылки на данные, которые не очищаются правильно? Убедитесь, что вы обнуляете дескрипторы, когда они больше не нужны, поскольку циклические зависимости приведут к большим утечкам.

0
ответ дан 2 December 2019 в 22:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: