Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Удаление объектов 
:(
    Опции темы
Freeman
Дата 23.2.2005, 19:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



Начал изучать C# и решил написать простенький список, но столкнулся с проблемой удаления объектов. Я знаю что в С# автоматическое удаление, но что если надо удалить элемент сразу, не дожидаясь пока это сделает сборщик мусора.
Если можно ответ, пояснить примером.
PM MAIL   Вверх
Domestic Cat
Дата 23.2.2005, 20:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 9
Всего: 172



Объект подлежит удалению тогда, когда на него нет ссылок - например, ссылка на него была в локальной переменной, или ты ее занулил. Тогда можно вызвать сборщик мусора, который и уберет ненужный объекt:

Код

myObject = null;
GC.Collect();


С другой стороны, в постоянном вызове сборщикa ничего хорошего нет .


--------------------

PM   Вверх
Gazon
Дата 23.2.2005, 23:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 128
Регистрация: 9.1.2005

Репутация: 3
Всего: 8



Цитата
С другой стороны, в постоянном вызове сборщикa ничего хорошего нет .

И с ним многие советуют не связываться ни в коем случае.
--------------------
Чем больше узнаешь, тем больше не знаешь, но до истины всегда можно добраться.
PM MAIL   Вверх
Tomcat
Дата 24.2.2005, 11:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 86
Регистрация: 4.4.2003
Где: Гродно, Беларусь

Репутация: 2
Всего: 2



Был у меня однажды случай. Прога была, в принципе, простенькая. Суть заключалась в том, что она собирала кучу информации с файлов, а потом одним махом заносила ее в БД на SQL Server. По началу все было не плохо... Но затем пошли файлы, у которых эта куча была слишком большой, да такой, что вылетал Out of memory. Когда посмотрели загруженность памяти, поняли, что все вполне понятно, выделяемая под процесс проги область разрасталась до 2-3 Гб, да плюс еще и SQL Server ел не мало.
Ну что же, и все из-за не удаленных промежуточных объектов, появляющихся при обработке файлов. Так вот, код типа:
Код

myObject = null;
GC.Collect();

не помогал вовсе. Беглый просмотр документации привел к выводу, что необходимо GC.Collect() вызывать два раза. Это тоже не помогало.
Нам тогда повезло, появились другие исходные данные, которые были намного удобней для обработки, на том и выехали.
PM MAIL   Вверх
Дрон
Дата 24.2.2005, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 24
Всего: 92



Посмотри метод Dispose для объёктов. Может поможет smile


--------------------
Да. Именно так.
PM   Вверх
Freeman
Дата 24.2.2005, 22:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



К сожалению ни один вариант не решил проблемы, но может я что-то не так делаю, вот код
Код

class List
{
 private class Node : IDisposable
 {
  public int val;
  public Node next;

  public Node() { }
  public Node(int v)
  {
   val = v;
  }
  public Node(int v, Node n)
  {
   val = v;
   next = n;
  }

  public void Dispose()
  {
   
  }
 }

 private int count;
 private Node head;

 public void Insert(int v)
 {
  Node pn = head, last = null, pnew;
 
  for (; pn != null  &&  pn.val <= v; last = pn, pn = pn.next);

  pnew = new Node(v);
  if (last == null)
  {
   pnew.next = head;
   head = pnew;
  }
  else
  {
   pnew.next = pn;
   last.next = pnew;
  }

  count++;
 }

 public void Show()
 {
  Node pn = head;
  int i = 0;

  Console.WriteLine("List...");
  while (pn != null)
  {
   Console.WriteLine("[{0}]: {1}", i, pn.val);
   i++;
   pn = pn.next;
  }
 }

 public bool Delete(int v)
 {
  Node pn = head, last = null;

  for (; pn != null && pn.val != v; last = pn, pn = pn.next);

  if (pn != null)
  {
   if (last != null)
   {
    last.next = pn.next;
   }
   else
   {
    head = pn.next;
   }
  }
  else
  {
   return false;
  }

  //так не помогает pn = null;
  //и так не помогаетGC.Collect();
  pn.Dispose(); //и так тоже
  count--;
  return true;
 }
}


а это тест

Код

class Program
{
 static void Main(string[] args)
 {
  List d = new List();
  int NN = 1000000;

  for (int i = NN-1; i > -1; i--)
  {
   d.Insert(i);
  }

  for (int i = 0; i < NN; i++)
  {
   d.Delete(i);
  }
 }
}


PM MAIL   Вверх
Domestic Cat
Дата 24.2.2005, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 9
Всего: 172



Код

private class Node : IDisposable
  {
   public int val;
       public Node next;
//....
         public void Dispose()
       {
             next = null; // на всякий случай 
     }
  }



Код

public bool Delete(int v)
  {
//...
    pn.Dispose(); 
    pn = null;
       count--;
         return true;
  }


1. Как ты определил что "не помогает"?
2. На кой из-за одного объекта в пару десяков байт вызывать сборщик?
Вроде никаких ошбок не вижу, хотя названия переменным можно было бы и поприличее дать.


--------------------

PM   Вверх
Plamenk
Дата 25.2.2005, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 258
Регистрация: 18.2.2003

Репутация: 1
Всего: 3



Вообще использование интерфейса IDisposable, никак не связано с удалением объекта!
Если класс реализует данный интерфейс, то подразумевается что он использует неуправляемые ресурсы и в функции Dispose просто происходит их очистка, так как сборщик мусора сам не сбособен освобождать такие ресурсы!

Что касается однозначного удаления объекта, то необходимо ИХМО как-то использовать GC и удалять все ссылки на объект!
PM MAIL   Вверх
Freeman
Дата 25.2.2005, 19:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



to Domestic Cat
Цитата
Как ты определил что "не помогает"?

Очень просто запустил тест и посмотрел в диспетчере задач, там есть объем занятой памяти, при удалении память должна освобождаться а она не освобождается

Цитата
На кой из-за одного объекта в пару десяков байт вызывать сборщик?

Так на всякий случай smile)

to Plamenk
Цитата
удалять все ссылки на объект!

Так они и так все удаляются, все локальные ссылки уничтожаются при выходе из функции,
есть правда указатели next ,но и они при таком коде

Код

public void Dispose()
{
     next = null;
}

они тоже обнуляются, так что не остаются никаких действующий ссылок на удаленный элемент.

Это сообщение отредактировал(а) Freeman - 25.2.2005, 19:57
PM MAIL   Вверх
Domestic Cat
Дата 25.2.2005, 20:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 9
Всего: 172



Цитата
Очень просто запустил тест и посмотрел в диспетчере задач, там есть объем занятой памяти, при удалении память должна освобождаться а она не освобождается


Дык посмотрi нa свой код - у тебя удаление идет в цикле. Расходуешь памяти ты немного, потом все объекты удаляешь. Вполне возможно что сборщик запускается при удалении, но диспетчер не успевает отобразить изменениe памяти.

[Offtop]
Кстати, вопрос : есть ли что нибудь наподобиe флагa -verbose:gc , как в Java?
[/Offtop]


--------------------

PM   Вверх
Freeman
Дата 25.2.2005, 22:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



to Domestic Cat
Проблема не в диспетчере, потому что точно такой же код написанный на обычном C++, работает как надо и диспетчер отображает освобождение памяти в реальном времени.
PM MAIL   Вверх
Дрон
Дата 26.2.2005, 01:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 24
Всего: 92



Цитата(Domestic @ 25.2.2005, 20:07)
Вполне возможно что сборщик запускается при удалении, но диспетчер не успевает отобразить изменениe памяти.

Сборщик мусора запускается тогда, когда сочтёт нужным.


Цитата(Domestic @ 25.2.2005, 20:07)
Кстати, вопрос : есть ли что нибудь наподобиe флагa -verbose:gc , как в Java?

А что он делает?

Это сообщение отредактировал(а) Дрон - 26.2.2005, 01:52


--------------------
Да. Именно так.
PM   Вверх
Domestic Cat
Дата 26.2.2005, 03:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 9
Всего: 172



Цитата
Сборщик мусора запускается тогда, когда сочтёт нужным.


Любой сборщик запускается когда захочет smile

Цитата
А что он делает?


Вывводит инфу - сколько с какой области хипа собрано. В Java есть поколения, только не 1, 2, 3 как в .НЕТ, а молодое и старое.
Что-то вроде
Цитата

.....
[GC 622K->110K(1984K), 0.0010317 secs]
[GC 622K->110K(1984K), 0.0010261 secs]
[GC 622K->110K(1984K), 0.0010359 secs]
[GC 622K->110K(1984K), 0.0010300 secs]
[GC 622K->110K(1984K), 0.0011647 secs]
[GC 622K->110K(1984K), 0.0010147 secs]
[GC 622K->110K(1984K), 0.0011021 secs]
[GC 622K->110K(1984K), 0.0010283 secs]
[GC 622K->110K(1984K), 0.0010306 secs]
[GC 622K->110K(1984K), 0.0010174 secs]
[GC 622K->110K(1984K), 0.0010345 secs]
[GC 622K->110K(1984K), 0.0018662 secs]
[GC 622K->110K(1984K), 0.0012367 secs]
.....



--------------------

PM   Вверх
Freeman
Дата 26.2.2005, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



Я вообще думал что это простой вопрос, неужели никто не делал каких-нибудь динамических структур на C#, хоть малюсенький дин. стек smile
PM MAIL   Вверх
Дрон
Дата 26.2.2005, 19:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 24
Всего: 92



Цитата(Freeman @ 26.2.2005, 18:36)
Я вообще думал что это простой вопрос, неужели никто не делал каких-нибудь динамических структур на C#, хоть малюсенький дин. стек smile

А в чём проблема? smile

Domestic Cat
Нет. По крайней мере, я такого не видел.


--------------------
Да. Именно так.
PM   Вверх
Domestic Cat
Дата 27.2.2005, 07:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 9
Всего: 172



Нашел я как делать.
1. Запускаем perfmon.exe из Выполнить.
2. Кликаем правой кнопкой на правой панели и выбираем "Добавить счетчики..."
3. Выбираем объект Память CLR .NET и Выбрать все счетчики
4. Нажимаем Добавить и Закрыть
5. Запускаем ченить НЕТовское и смотрим, лучше под видом "Просмотр отчета".



--------------------

PM   Вверх
Freeman
Дата 27.2.2005, 08:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



to Дрон
Проблема в том, что удаление не работает так как должно.
PM MAIL   Вверх
Domestic Cat
Дата 27.2.2005, 09:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 9
Всего: 172



Цитата(Freeman @ 26.2.2005, 23:57)
Проблема в том, что удаление не работает так как должно.


Все на самом деле работает. Если не веришь - вот пример:
Код

class Class1
{
 static ArrayList list = new ArrayList();
 /// <summary>
 /// The main entry point for the application.
 /// </summary>
 
 [STAThread]
 static void Main(string[] args)
 {
  long totalMemory = GC.GetTotalMemory(true);
  Console.WriteLine("Was: " + totalMemory);
  FillList();
  totalMemory = GC.GetTotalMemory(true);
  Console.WriteLine("Before removing: " + totalMemory);
  RemoveAllFromList();
  totalMemory = GC.GetTotalMemory(true);
  Console.WriteLine("After removing: " + totalMemory);
 }

 private static void FillList()
 {
  for (int i = 0; i < 1000; i++)
   list.Add(new Object());
 }

 private static void RemoveAllFromList()
 {
  for (int i = 1000; i > 0; i--)
   list.RemoveAt(0);
 }
}


Результат:
Цитата
Was: 45116
Before removing: 64200
After removing: 52200


64200 - 52200 = 12000 байт
Всего объектов 1000 - значит, по 12 байт на каждый Объект, как и должно быть. То есть, все объекты после метода RemoveAllFromList были вычищены.


--------------------

PM   Вверх
Freeman
Дата 27.2.2005, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



to Domestic Cat
Я не спорю с ArrayList все работает, но я не думаю что в реальном приложении Вы будете пользоваться таким списком. По-крайней мере из-за двух причин :
1. Слишком медленный(в части удаления), запустите Ваш пример не на 1000, а на 100000 и больше.
2. Расход памяти одинаковый для любых объектов, и равен <размер списка>*sizeof(Object), что наводит на мысль что в ArrayList хранятся не сами объекты, а лишь ссылки на них, причем ссылки типа Object, из-за этого возникает дополнительная трудоемкость, более того если со ссылочными типами происходит только преобразование типа, то со структурными типами происходит упаковка объекта, что также не улучшает эффективность данной структуры.
3. Если можно, не могли бы Вы объяснить следующую вешь.
Was: 211380
Before: 1938880
After: 738868
почему разница между After - Was, такая большая?

А вот если Вы поставите в нужные места в моем незамысловатом коде следующий код
Код

memory = GC.GetTotalMemory(true);
Console.WriteLine(".....: {0}", memory);

то получатся следующие результаты
Was: 216656
Before: 1819012
After: 219012

Тестирование в обоих случаях проводилось на 100000.
PM MAIL   Вверх
Domestic Cat
Дата 27.2.2005, 11:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 9
Всего: 172



Цитата(Freeman @ 27.2.2005, 01:44)
но я не думаю что в реальном приложении Вы будете пользоваться таким списком.


Почему не буду, буду. Свое-то точно сочинять не собираюсь.

Цитата(Freeman @ 27.2.2005, 01:44)
Слишком медленный(в части удаления), запустите Ваш пример не на 1000, а на 100000 и больше.

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

Цитата(Freeman @ 27.2.2005, 01:44)
Расход памяти одинаковый для любых объектов, и равен <размер списка>*sizeof(Object), что наводит на мысль что в ArrayList хранятся не сами объекты, а лишь ссылки на них,

Само собой

Цитата(Freeman @ 27.2.2005, 01:44)
причем ссылки типа Object

Да, Объект, иначе он бы вообще ничего не смог хранить. Не устраивает - есть generics.

Цитата(Freeman @ 27.2.2005, 01:44)
ссылочными типами происходит только преобразование типа, то со структурными типами происходит упаковка объекта, что также не улучшает эффективность данной структуры.

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

Цитата(Freeman @ 27.2.2005, 01:44)
почему разница между After - Was, такая большая?

Помимо твоих объектов, нахипе создаются и другие, которые ты "не видишь". Например простейшая операция
Код

string с = "Хелло " + "Ворлд!";

создает как минимум 3 объекта.
Помимо этого, getTotalMemory не всегда выдает точное значение.


Цитата(Freeman @ 27.2.2005, 01:44)
то получатся следующие результаты
Was: 216656
Before: 1819012
After: 219012


Вроде ж все пучком, объекты удаляются, разве не так?


--------------------

PM   Вверх
Freeman
Дата 27.2.2005, 14:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



Объекты удаляются лишь виртуально, физическая память не освобождается. Это аналогично работе "Корзины" в Винде, вроде бы файлы удаляются, но место на диске все равно жрут, по не очистишь smile

Цитата
Помимо твоих объектов, нахипе создаются и другие, которые ты "не видишь".

И как я понял они не удаляются.

Список это достаточно простая структура, и она заранее реализована. Но если мне нужно допустим какое-нибудь дерево или граф, я что-то не нашел ничего подобного.
PM MAIL   Вверх
Дрон
Дата 27.2.2005, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 24
Всего: 92



Freeman
Чегой-то я не понимаю, в чём же всё-таки у тебя проблема?
Такова уж особенность систем с автоматической сборкой мусора smile

Хочется самостоятельно управлять памятью? Так напиши на Си какую-нибудь библиотеку, сделай там функции аналогичные malloc и free, подключи в .NET и используй их (хотя это бредовая и бесполезная идея) smile


--------------------
Да. Именно так.
PM   Вверх
Freeman
Дата 1.3.2005, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 29.11.2003

Репутация: нет
Всего: нет



Проблема была в том что удаление работало на половину, из кучи объекты удалялись, а из физической памяти нет. Но в конце концов я понял в чем была причина. Все дело было в сборщике мусора, он не работает в Visual Studio 2005 Beta 1, по крайней мере так как должен. Но у меня имеется также и 2003 там все работает прекрасно.
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1140 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.