03 December 2013

Integer cache

Есть такая известная задачка, что напечатает в консоль данный код:

Казалось бы очевидно - везде '127', но не все так просто. В Java для оптимизации числа объектов был разработан так называемый Integer cache (некий аналог String pool):

Аналогичный кэш существует и для оберток типа Long:

По-умолчанию размер кэша - 256 и заполнен числами в интервале [-128; 127]. Но размер можно изменить:
  • -XX:AutoBoxCacheMax=XXXX - увеличивает размер кэшей (Integer, Long) до XXXX + 128, где будут храниться значения в интервале [-128; XXXX];
  • -XX:+AggressiveOpts - опция изменяет значения множества опций, среди которых увеличивает AutoBoxCacheMax до 20 000;
  • -Djava.lang.Integer.IntegerCache.high=XXXX - данная опция по аналогии с AutoBoxCacheMax увеличивает размер кэша, только в данном случае только для объектов типа Integer.
Вся хитрость задачи, приведенной в начале, заключается в том, что с помощью рефлексии можно получить доступ к внутреннему значению Integer и изменить его:

Таким образом, мы значение '127' заменяем на '0' и код, приведенный в начале, в 1-ом и 3-ем случае выведет '0'! В 1-ом случае мы выводим измененный объект 'x', во 2-ом - будет вызван метод println(int x) и боксинг не произойдет, в 3-ем случае произойдет боксинг и возьмется значение из кэша, в 4-ом - мы явно создаем объект в обход кэша.

Такие дела,
Иван

08 October 2013

Утилиты в составе JDK / Standard JDK utilities

В составе JDK, помимо всем известных javac, java, есть ещё несколько полезных утилит:


Имя утилиты              Размер (байт)


jconsole.exe                        16,776
jinfo.exe                               16,264
jmap.exe                              16,264
jstack.exe                             16,264
javap.exe                              15,752
jhat.exe                                15,752
jps.exe                                  15,752
jstat.exe                                15,752

Я не случайно привел размер каждой утилиты, так как он практически у всех идентичный (~16-17 Кб). По факту, каждая из утилит реализована на Java, а в момент сборки в качестве шаблона используется простейшая утилита реализованная на языке C, которая ищет JRE, затем парсит аргументы, создает JVM, ищет Java-класс утилиты и вызывает соответствующий метод main. Исходной код можно найти здесь (${JDK_SOURCE}/jdk/src/share/classes/sun/ или ${JDK_SOURCE}/langtools/src/share/classes/com/sun/tools/).

Любую из утилит можно использовать в своем приложении. Для этого необходимо в classpath добавить библиотеку tools.jar (${JDK_DIR}/lib/tools.jar).

Рассмотрим самые наиболее популярные из них.

jps 

(sun.tools.jps.Jps)
Утилита показывающая список JVM (в формате < ID процесса > < Main класс >) запущенных локально или удаленно (для этого необходимо в параметрах хост удаленной системы).

jconsole 

(sun.tools.jconsole.JConsole)
Графическая утилита для мониторинга JVM запущенной на локальной или удаленной системе. JConsole использует расширенные возможности JVM и предоставляет информацию касательно производительности, потребляемой памяти, потоков приложения, загруженных классов. Запустить утилиту можно из командной строки введя команду jconsole (появится диалоговое окно выбора JVM для мониторинга), также в качестве параметров можно указать ID процесса (если JVM запущена локально) или имя хоста и порт (если JVM запущена удаленно).



jinfo 

(sun.tools.jinfo.JInfo)
Утилита позволяющая узнать конфигурацию запущенной JVM (для этого в параметрах нужно указать ID процесса): версию JVM, системные параметры, флаги.

jmap 

(sun.tools.jmap.JMap)
Утилита показывающая список объектов разделяемой памяти (shared object memory), либо объектов находящихся в heap'е. Для запуска утилиты необходимо указать ID процесса. В зависимости от параметров возможно получение следующей информации:

  • Если нет дополнительных аргументов, то выводится список объектов разделяемой памяти. Для каждого объекта указывается стартовый адрес, размер маппинга и полный путь до файла данного объекта.
  • -dump:format=b,file=< путь к файлу для дампа > - создается дамп heap'a в бинарном формате hprof. Для того чтобы просмотреть объекты находящиеся в дампе можно воспользоваться стандартной утилитой jhat (будет рассмотрена далее), либо использовать более удобное средство - Eclipse Memory Analyzer.
  • -finalizerinfo - выводит список объектов ожидающих финализацию (finalization).
  • -histo - выводит гистограмму объектов находящихся в heap'e. Для каждого класса выводится информация о количестве объектов, размере используемой памяти.
  • -permstat - выводит расширенную статистику по загрузчикам классов (class loader). Для каждого загрузчика классов выводится его имя, адрес, родительский загрузчик классов (parent class loader), количество и размер загруженных классов.

jstack 

(sun.tools.jstack.JStack)
Утилита печатающая все стэктрэйсы (stacktrace) JVM запущенной локально (необходимо указать ID процесса), либо удаленно (< ID процесса >@< IP адрес системы на которой запущена JVM >). Если утилита запущена с параметром -m (mixed mode), то также выводится стэктрэйс нативных методов.

javap 

(com.sun.tools.javap.Main)
Утилита позволяющая декомпилировать class-файл. В качестве параметра необходимо указать путь к файлу класса. В зависимости от параметров возможно получение следующей информации:

  • Если нет дополнительных параметров, то выводится информация о пакете класса (package), родительский класс, список методов и их сигнатуры.
  • -c - В дополнении к базовой информации о классе, выводится список байткодов.
  • -verbose - Выводит информацию о размере стека, количестве локальных переменных и аргументов.
Из всех параметров самый важный это verbose - с помощью него можно получить практически всю информацию о классе.

jhat 

(com.sun.tools.hat.Main)
Утилита позволяющая анализировать heap дампы через веб интерфейс и DSL OQL (Object Query Language) (SQL-подобный язык запросов) . Дамп для анализа можно получить одним из следующих способов:

  • Использовать утилиту jmap (была описана ранее);
  • С помощью утилиты jconsole (была описана ранее) можно получить дамп используя MBean HotSpotDiagnosticMXBean;
  • Дамп будет сгенерирован в случае возникнования OutOfMemory и при этому у JVM была указана опция -XX:+HeapDumpOnOutOfMemoryError;
  • Использовать утилиту hprof.
Помимо самого дамп файла, в качестве параметров можно указать порт для веб интерфейса (по умолчанию 7000).




jstat 

(sun.tools.jstat.Jstat)


Такие дела,
Иван.



29 August 2013

Array initialization

Java class file stores array initializers as a sequence of explicit array-element initializers, equivalent to data[0]=1, data[1]=2; data[2]=3; instead of comcact block of packed bytes.

19 August 2013

JVM internals: Runtime data areas

When a Java virtual machine runs a program, it needs memory to store many things, including bytecodes and other information it extracts from loaded class files, objects the program instantiates, parameters to methods, return values, local variables, and intermediate results of computations. The Java virtual machine organizes the memory it needs to execute a program into several runtime data areas.

Overview of all data areas:


Let's talk about each one in detail. 

Data areas individual for each thread:
  1. The pc Register - program counter register. Each JVM thread has its own pc register. At any time JVM thread executing method and if that method is not native, the pc register contains the address (in Method Area) of next instruction to execute, but is method is native then pc register's value is undefined. 
  2. Stack. JVM stack stores the state of each Java (not native) method invocations for the thread. State of method invocation placed in stack frame (or simply frame), so then thread invokes method, new frame created and pushed to stack, and then method completes frame poped and discarded from virtual machine. State of frame contains local variables, parameters of method, return result, intermediate calculations also know as operand stack (as JVM is stack-based VM, it has no registers to store intermediate calculations) and reference to current class constant pool. The sizes of local variable array and the operand stack are determined at compile-time. Only one frame is active at any point of thread execution and this frame is called current frame and it's method known as current method. It should be mention, the memory for JVM stack doesn't have to be contiguous.
  3. Native Method Stack. Native method stack also called as "C stack". Native method stack is used for native method invocation and also may be used by the implementation of a JVM bytecode interpreter. 

Interaction between Java stack and Native Method Stack:


Data areas shared by all threads:
  1. Heap. 
  2. Method Area. Method area is used to store per-class structures such as runtime constant pool, field and method data, code for methods and constructors (including special methods used in class or object initialization). Method area is created on virtual machine start up and it is logical part of heap. JVM provide control over minimum and maximum size of method area or just initial size.
  3. Runtime Constant Pool. Runtime constant pool is per-class or per-interface runtime representation of the constant_pool table in a class file. It contains several kinds of constants ranging from literal constants known at compile time to method and field references resolved at runtime. Runtime constant pool is constructed when class or interface created in virtual machine.
    In class file constant pool is represented as array of structures like:
                

      constant_info {
                u1 tag;
                u1 info[];
    }

    Tag is 1 byte value which is vary from 1 to 18 and represents one of constant type.

    ·         CONSTANT_Utf8  (1)
    u1 tag – constant type (1)
    u2 length – number of bytes in byte array
    u1 bytes[length] – contains bytes of string (byte value > 0 i. e. in range (0; 0x0F)) (strings                                      is encode in modified UTF-8)

    ·         CONSTANT_Class  (7)
    tag - constant type (7)
    name_index -  index of CONSTANT_Utf8 entry in constant_pool

    ·         CONSTANT_FieldRef (9)

    ·         CONSTANT_MethodRef (10)

    ·         CONSTANT_InterfaceMethodRef (11)
    u1 tag – constant type
    u2 class _index – index of CONSTANT_Class entry in constant pool
    u2 name_index – index of CONSTANT_NameAndType entry in constant pool

    ·         CONSTANT_String (8)
    u1 tag – constant type (8)
    u2 string_index – index of CONSTANT_Utf8 entry in constant pool to which the String object is to be initialized

    ·         CONSTANT_Integer (3)

    ·         CONSTANT_Float (4)
    u1 tag – constant type
    u4 bytes – value of constant in bytes in big-endian order (high order first)

    ·         CONSTANT_Long (5)

    ·         CONSTANT_Double (6)
    u1 – constant type
    u4 hight_bytes
    u4 low_bytes
    VALUE = ((long) high_bytes << 32) + low_bytes

    ·         CONSTANT_NameAndType (12)
    u1 tag – constant type
    u2 name_index – method or field name
    u2 descriptor_index – method or field descriptor
    Field descriptor –
    §  B – byte
    §  C – char
    §  D – double
    §  F – float
    §  I – integer
    §  J – long
    §  L ClassName ; - reference
    §  S – short
    §  Z – Boolean
    §  [ - array dimension (one bracket per dimension)
    Method descriptor – (FieldDescriptor*)ReturnDecriptor  (return descriptor may be V – void or FieldDescriptor)

    ·         CONSTANT_MethodHandle (15)
    u1 tag – constant type
    u1 reference_kind – value denotes the kind of method handle, which characterizes its bytecode behavior and lies in range 1 to 9
    1.       REF_getField + CONSTANT_Field
    2.       REF_getStatic + CONSTANT_Field
    3.       REF_putField + CONSTANT_Field
    4.       REF_putStatic + CONSTANT_Field
    5.       REF_invokeVirtual + CONSTANT_MethodRef (all methods excluding and )
    6.       REF_invokeStatic + CONSTANT_MethodRef (all methods excluding and )
    7.       REF_invokeSpecial + CONSTANT_MethodRef (all methods excluding and )
    8.       REF_newInvokeSpecial + CONSTANT_MethodRef (only )
    9.       REF_invokeInterface + CONSTANT_InterfaceMethodRef (all methods excluding and )
    u2 reference_index – value of CONSTANT_Field, _MethodRef, _InterfaceMethodRef

    ·         CONSTANT_MethodType (16)
    u1 tag – constant type
    u2 descriptor_index – valid index of CONSTANT_Utf8 entry in constant_pool which representing a method descriptor

    ·         CONSTANT_InvokeDynamic (18)
    u1 tag – constant type
    u2 bootstrap_method_attr_index – valid index of bootstrap_methods array of the bootstrap method table of current class file
    u2 name_and_type_index – valid index of CONSTANT_NameAndType entry in constant_pool representing method name and method descriptor


JVM internals: VM types

Like the Java programming language JVM operated two kinds of types: primitive and reference types.

All type checking performed by compiler, and does not have to be done by JVM.

VM primitive data types:
  • numeric
    • byte - 8-bit signed / [-128;127];
    • short - 16-bit signed [-32768; 32767];
    • char - 16-bit unsigned [0; 65535];
    • int - 32-bit signed [-2147483648; 2147483647];
    • float - 32-bit precision (IEEE 754 standard);
    • long - 64-bit signed [-;];
    • double - 64-bit precision (IEEE 754 standard).
  • boolean - JVM provides limited support to boolean data type. There are no VM instructions solely dedicated to operation on boolean type. Expressions to operate boolean type are compiled to use int data type (int value 1 - true, int value 0 - false). JVM directly supports boolean arrays as byte arrays (so it using 8 bytes per boolean value and bytecode instructions that are also suitable for byte arrays):
    • newarray - creates boolean array;
    • baload - access to boolean array;
    • bastore - modify boolean array.
  • returnAddress - returns pointer to the opcodes of JVM instructions. The data type used by JVM instructions: jsr, jsr_w, ret. Anlilke other JVM datatypes, returnAddress doesn't correspond to any Java programming language type and cannot be modified by running program.
VM reference types:
  • class types;
  • interface types;
  • array types.
A VM reference may be null reference - reference to no object and default value of any reference. Null reference initialy in runtime has no type, but may be cast to any reference type.