Почему моя программа Java пропускает память, когда я называю выполненными () на объекте Потока?

Это довольно распространенная проблема. Вы используете | DataDirectory | строка подстановки. Это означает, что при отладке вашего приложения в среде Visual Studio база данных, используемая вашим приложением, находится в папке подпапки BIN\DEBUG (или версии x86) вашего проекта. И это хорошо работает, так как у вас нет какой-либо ошибки, связанной с базой данных и выполняющей операции обновления.

Но затем вы выходите из сеанса отладки и просматриваете свою базу данных через Visual Studio Server Explorer. Это окно имеет другую строку подключения (возможно, указывая на копию вашей базы данных в папке проекта). Вы просматриваете свои таблицы, и вы не видите изменений.

Затем проблема ухудшается. Вы перезапускаете VS, чтобы искать ошибку в своем приложении, но у вас есть файл базы данных, указанный между вашими файлами проекта, а для свойства Copy to Output directory установлено значение Copy Always. На этом этапе Visual Studio копирует исходный файл базы данных из папки проекта в выходную папку (BIN \ DEBUG), и поэтому ваши предыдущие изменения теряются. Теперь ваше приложение снова вставляет / обновляет целевую таблицу и вы не можете найти никаких ошибок в коде. (Теперь я не знаю, являетесь ли вы таким парнем, но после двух или трех раз этого цикла я слышал разные уродливые слова)

Вы можете остановить эту проблему, изменив свойство Copy To Output Directory - Copy If Newer или Never Copy. Также вы можете обновить строку соединения в проводнике сервера, чтобы посмотреть на рабочую копию базы данных или создать второе соединение. Первый по-прежнему указывает на базу данных в папке проекта, а второй указывает на базу данных в папке BIN \ DEBUG. Таким образом, вы можете сохранить исходную базу данных в целях развертывания и изменения схемы, в то время как со вторым соединением вы можете посмотреть на эффективные результаты ваших усилий по кодированию.

EDIT Специальное предупреждение для базы данных MS-Access пользователи. Простой взгляд на таблицу изменяет дату изменения базы данных ТАКЖЕ, если вы ничего не пишете и не меняете. Таким образом, флаг Copy if Newer запускается, и файл базы данных копируется в выходной каталог. С Access лучше использовать Copy Never.

27
задан 3 revs, 2 users 100% 26 September 2008 в 09:26
поделиться

3 ответа

Это - известная ошибка в Java 1.4: http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=5869e03fee226ffffffffc40d4fa881a86e3:WuuT?bug_id=4533087

Это фиксируется в Java 1.5, но Sun не намеревается зафиксировать его в 1,4.

проблема - то, что, во время создания, Thread добавляется к списку ссылок во внутренней таблице потока. Это не будет удалено из того списка до своего запуска (), метод завершился. Пока та ссылка там, она не будет собрана "мусор".

Так, никогда не создавайте поток, если Вы определенно не собираетесь назвать start() метод. Thread объект run() метод нельзя назвать непосредственно.

А лучший способ кодировать его состоит в том, чтобы реализовать эти Runnable интерфейс, а не подкласс Thread. Когда Вам не нужен поток, звоните

myRunnable.run();

при необходимости в потоке:

Thread myThread = new Thread(myRunnable);
myThread.start();
47
ответ дан 4 revs, 2 users 85% 14 October 2019 в 13:48
поделиться

Я сомневаюсь, что построение экземпляра Потока или подкласса этого пропускает память. Во-первых, нет ничего из видов, упомянутых в Javadocs или Спецификации языка Java. Во-вторых, я запустил простой тест, и он также показывает, что никакая память не пропущена (по крайней мере, не на JDK Sun 1.5.0_05 на 32-разрядном x86 Linux 2.6):

public final class Test {
  public static final void main(String[] params) throws Exception {
    final Runtime rt = Runtime.getRuntime();
    long i = 0;
    while(true) {
      new MyThread().run();
      i++;
      if ((i % 100) == 0) {
        System.out.println((i / 100) + ": " + (rt.freeMemory() / 1024 / 1024) + " " + (rt.totalMemory() / 1024 / 1024));
      }
    }
  }

  static class MyThread extends Thread {
    private final byte[] tmp = new byte[10 * 1024 * 1024];

    public void run() {
      System.out.print(".");
    }
  }
}

РЕДАКТИРОВАНИЕ: Только суммировать идею теста выше. Каждый экземпляр подкласса MyThread Потока ссылается на свой собственный массив на 10 МБ. Если бы экземпляры MyThread не были собраны "мусор", JVM исчерпала бы память довольно быстро. Однако выполнение тестового кода показывает, что JVM использует маленький постоянный объем памяти независимо от числа MyThreads, созданного до сих пор. Я утверждаю, что это вызвано тем, что экземпляры MyThread собраны "мусор".

3
ответ дан Alexander 14 October 2019 в 13:48
поделиться

Давайте посмотрим, могли ли мы стать ближе к ядру проблемы:

, Если Вы запускаете свою программу (позволяет, говорят), 1000 использований x запускаются (), тогда 1000 x использование выполненного () в потоке, действительно оба освободите память? Если так, тогда Ваш алгоритм должен быть проверен (т.е. на внешние объекты, такие как Векторы, используемые в Вашем Выполнимом).

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

2
ответ дан Georgi 14 October 2019 в 13:48
поделиться
Другие вопросы по тегам:

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