Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Выделение памяти под массив


Автор: UnicornMirage 28.2.2006, 00:14
любой массив объектов в Java хранит ссылки на объекты (какими они ни были эти объекты). отсюда следует что все проинициализированные массивы будут занимать одинаковый объем памяти? (разумеется учитывается только массив ссылок на объекты а не сами проинициализированные объекты):

Код

MyObject[] arr_1 = {new MyObject(1), new MyObject(2), ..., new MyObject(n)}
File[] arr_2 = new File[n];
String[] arr_3 = new String[n];

для всех равных n


сколько байт занимает одна ссылка?

Автор: redrick 28.2.2006, 01:18
Вобщем, в спецификации VM это не оговаривается.
Одна ссылка может занимать сколько угодно, в зависимости от реализации. На практике, правда, это обычно 4 байта.
А насчет одинаковости - опять же, скорее всего, но не обязательно, обязательно только то что по данной ссылке ты сможешь вытащить объект которым ее проинициализировал.

Автор: LSD 28.2.2006, 10:58
На 64-х битных машинах, скорее всего одна ссылка будет занимать 8 байт. А вообще это не сложно узнать:
Код
  public static void main(String[] args)
  {
    int size = 1024 * 1014;
    Runtime runtime = Runtime.getRuntime();
    doGC();
    long before = runtime.totalMemory() - runtime.freeMemory();
    Object[] obj = new Object[size];
    long after = runtime.totalMemory() - runtime.freeMemory();
    System.out.println("sizeof(Object[" + size + "]) = " + (after - before) + " bytes, " + ((after - before) / (double) size) + " bytes/element");
  }

  private static void doGC()
  {
    System.gc();
    System.gc();
    System.gc();
    System.gc();
  }

Автор: powerOn 28.2.2006, 11:58
Цитата

Код

 private static void doGC()    
  {    
    System.gc();    
    System.gc();    
    System.gc();    
    System.gc();    
  }



Простите, а зачем 4 раза сборщик мусора поднимать?

Автор: redrick 28.2.2006, 12:04
Цитата(MoonCat @ 28.2.2006, 11:58 Найти цитируемый пост)
ростите, а зачем 4 раза сборщик мусора поднимать?

для пущей лучшести =)

Автор: LSD 28.2.2006, 12:08
А щоб наверняка smile
1. Вызов System.gc() не гарантирует, что сборщик будет реально вызван
Цитата
Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse.

2. Сборщик мусора инкрементальный, и может не все объекты очистить после первого вызова.

Это уже обсуждалось, если найду кину ссылку.

Автор: UnicornMirage 28.2.2006, 14:15
спасибо за ответы.
теперь отвечу почему я задал такой вопрос - например есть задача - где необходимо выделить своеобразный КЭШ для объектов произвольного типа. размер КЕШа заранее известен, также известен его максимально-возможный размер.. и в этом случае целесообразнее использовать заранее выделенный массив ссылок на объекты, чем использовать коллекции или списки, т.к. это будет работать гораздо быстрее?


Автор: redrick 28.2.2006, 14:23
если у тебя в кеше лежат большие объекты (уж побольше чем 4 или 8 байт) то, думаю, колекция маленьких ссылок не испортит тебе жизнь

Вобщем незачем этот массив заранее выделять - ничего это не дает.

Автор: COVD 28.2.2006, 17:50
Цитата

это будет работать гораздо быстрее?


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

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

Автор: king 9.4.2006, 17:41
То что указатель занимает 4 байта понятно.. Но меня еще интересует другой вопрос : сколько занимает сам объект .. Немного модернизировал ваш код :

Код

public class MemoryTest
{
    
    public static void main(String[] args)
      {
        int size = 1024 * 1014;
        Runtime runtime = Runtime.getRuntime();
        doGC();
        long before = runtime.totalMemory() - runtime.freeMemory();
        Test[] obj = new Test[size];
        for (int i = 0; i < size; i++ )
        {
         obj[i] = new Test();

        }
        
        long after = runtime.totalMemory() - runtime.freeMemory();
        System.out.println("sizeof(Test[" + size + "]) = " + (after - before) + " bytes, " + ((after - before) / (double) size) + " bytes/element");
      }

      private static void doGC()
      {
        System.gc();
        System.gc();
        System.gc();
        System.gc();
      }

}



и получил :

sizeof(Test[1038336]) = 20771840 bytes, 20.004930966469427 bytes/element

т.е 20 байтов на элемент. Из них 4 идет на указатель.. а 16 на объект..
После эксперементов установил следующую закономерность :
0 полей - 8 байт
1 интовое поле - 16 байт
2 интовых поля - 16 байт
3 интовых поля - 24 байт
4 интовых поля - 24 байт
5 интовых поля - 32 байт

т.е пустой клас занимает 8 байт, дальше идет выравнивание размера на 8 байт .. Это нормальное поведение для ява програмы? просто получается что большое количество объектов создавать не выгодно в яве.. в с++ можно делать структуры (это фактичнски те же самые классы) , но весят они именно столько , сколько от них ждешь

Автор: powerOn 9.4.2006, 19:21
А класс Test как выглядит?

Автор: LSD 9.4.2006, 20:54
Цитата(king @ 9.4.2006, 18:41 Найти цитируемый пост)
Это нормальное поведение для ява програмы?

Это зависит от реализации JVM, но вообщем поведение нормальное.


Цитата(king @ 9.4.2006, 18:41 Найти цитируемый пост)
получается что большое количество объектов создавать не выгодно в яве.. в с++ можно делать структуры (это фактичнски те же самые классы) , но весят они именно столько , сколько от них ждешь

Если ты будешь создавать структуры с парой чисел типа int (например координаты), и создавать их миллионами. То с помощью структур это делать выгодней. Но если у тебя храняться сколько нибудь объемные данные, то 8 байт тебе погоды не сделают.

Автор: king 10.4.2006, 08:28
Цитата(MoonCat @ 9.4.2006, 19:21)
А класс Test как выглядит?

Код

class Test
{
    int p = 10;
}

Автор: powerOn 10.4.2006, 11:28
Цитата

в с++ можно делать структуры (это фактичнски те же самые классы) , но весят они именно столько , сколько от них ждешь


В С++ структуры весять как сумма "масс" полей, но это структуры. В Java нет структур. В Java есть классы.
А это означает, что любой класс, даже такой:
Цитата

class Test
{
    int p = 10;
}


будет наследован от класса Object, который в свою очередь тоже требует определенного объема памяти.

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

Код

Vector v = new Vector();
v.addElement(new Float(10.5);
v.addElement(new Integer(20));
v.addElement(new Vector());


, поскольку есть метод addElement(Object o). И не важно кто есть o. Это дает дополнительную гибкость.

И вообще, если даже на MFC посмотреть, там тоже большинство классов унаследованны от CObject, который, вероятно, тоже занимает определенное место в памяти. smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)