среда, 1 августа 2012 г.

module: java memory


Подтемы
    - permanent generation/PermGen

    Немного используемой терминологии:

    - с точки зрения JVM: деление на требования спецификации (jvmspec) и особенности конкретной реализации (HotSpot, ? HotSpot TLAB, G1, CMS, ...)
    - с точки зрения JVM: деление на формулировки спецификации (jvmspec) и особенности конкретного поведения в конкретной реализации (object allocation in stack, lock coarcesing, ...)


    Terms: stack, 

2.5 Runtime Data Areas
2.5.2 Java Virtual Machine Stacks

TODO: добавь возврат, а не только передачу



Поколенческая гипотеза - ?
разница между спекой и реализацией - ?
    - хотспот
    - ibm
    - bea
    - oracle - oc4j
    - azul
    - dalvic
    - j2me
    - ...

слияние HotSpot и JRockit - ?
стек непрерывен - ?
стек фиксированного размера при создании - не растет - ?
стек берется из общего места с хипом - ?
хип - растет, но убывает ли - ?
компакт коллектор - ?
копи коллектор - ?
парал коллектор - ?
коекур коллектор - ?
поколенческий коллектор - ?
в памяти может быть несколько коллекторов - ?
 - ?
 - ?
 - ?
 - ?
 - ?
 - ?
 - ?
 - ?

    Примитивы состоят из одной части.
    Ссылочные типы состоят из двух частей.
    Object obj = null; = только ссылающееся
    new Object(); = только ссылаемое
    Примитивы передаются по значению. Ссылку на примитив и ссылающееся невозможно разделать.



Факты
    Современные GC работают на основе поиска достижимых объектов, а не подсчета ссылок. Для них не составляют проблем циклические ссылки и время их работы пропорционально количеству живых объектов, а не выделенных.
    В Sun HotSpot присутствуют несколько GC, можно выбрать один из них.
    В Sun HotSpot Java 7 добавился G1 коллектор.
    "Слабая поколенческая гипотеза" - большинство объектов умрут молодыми.
    System.gc() - носит рекомендательный характер и каждая JVM сама решает как реагировать. Конкретно у Sun HotSpot - вызывается stop-the-world gc. Избегайте этого.
    Параллельный коллектор - это коллектор, состоящий из нескольких потоков. ??? - параллельный.
    Конкурентный коллектор - это коллектор, работающий одновременно с рабочими потоками. ??? - конкурентный.
    Момент запуска finalize() - не определен и запуск может вообще не состояться.
    Object.hashCode() - это не адрес объекта. 
    В Java начиная с 1.4.2 (добавилось NIO = java.nio.*) можно выделять объекты за пределами heap. Ссылки хранятся в heap, но указывают за его пределы. ByteBuffer.allocateDirect(...). Соответственно возможна "настоящая" "утечка памяти".


Материалы
Heap, stack
    - [Шилдт. Руководство] - стр 149-151
Передача по ссылке/по значению
    - [Шилдт. Руководство] - стр 172-174
GC, finalize
    - [Шилдт. Руководство] - стр 161-162

Задания
    - задания по "уборке мусора" (garbage collector, gc)

Словарь
"Уборка мусора", garbage collection, "уборщик мусора", garbage collector, недостижимые объекты, утечка памяти (memory leak)

План

Лекция #4 (память)
    Внешняя и внутренняя память JVM, деление внутренней на stack, heap и PermGen.
    Stack и Heap: геометрия размещения объектов, где хранятся локальные переменные, где хранятся поля, где хранятся статические поля, различие между примитивными и ссылочными типами, передача по ссылке/по значению.
    Heap и GC: разделение объектов - проблема освобождения памяти, понятие уборки мусора/уборщика мусора, цикл подсистемы памяти (new-gc), циклические ссылки, понятие достижимого объекта, поиск достижимых объектов, работа finalize().
Тесты: 
    - передача по ссылке/по значению
    - достижимы ли объекты
Лабораторная
    Циклический буфер - исправить недоделку.
Доп-инфа: 
    Исчерпание PermGen загрузкой классов.
    Условия при которых возможно выгрузить класс.


Материалы для углубленного изучения

JVM spec:
    2.5 Runtime Data Areas
    "The Java virtual machine defines various runtime data areas that are used during execution of a program. Some of these data areas are created on Java virtual machine start-up and are destroyed only when the Java virtual machine exits. Other data areas are per thread. Per-thread data areas are created when a thread is created and destroyed when the thread exits."
    2.5.2 Java Virtual Machine Stacks
    "Each Java virtual machine thread has a private Java virtual machine stack, created at the same time as the thread. A Java virtual machine stack stores frames (§2.6). A Java virtual machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java virtual machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java virtual machine stack does not need to be contiguous."
    "This specification permits Java virtual machine stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the Java virtual machine stacks are of a fixed size, the size of each Java virtual machine stack may be chosen independently when that stack is created.
    A Java virtual machine implementation may provide the programmer or the user control over the initial size of Java virtual machine stacks, as well as, in the case of dynamically expanding or contracting Java virtual machine stacks, control over the maximum and minimum sizes."
    2.5.3 Heap
    "The Java virtual machine has a heap that is shared among all Java virtual machine threads. The heap is the runtime data area from which memory for all class instances and arrays is allocated.
    The heap is created on virtual machine start-up. Heap storage for objects is
reclaimed by an automatic storage management system (known as a garbage
collector); objects are never explicitly deallocated. The Java virtual machine
assumes no particular type of automatic storage management system, and the storage management technique may be chosen according to the implementor's system requirements. The heap may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger heap becomes unnecessary. The memory for the heap does not need to be contiguous."
    2.5.4 Method Area
    "The Java virtual machine has a method area that is shared among all Java virtual machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the runtime constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
    The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This version of the Java virtual machine specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous."
    2.5.5 Runtime Constant Pool
    2.6 Frames
    "A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception). Frames are allocated from the Java virtual machine stack (§2.5.2) of the thread creating the frame. Each frame has its own array of local variables (§2.6.1), its own operand stack (§2.6.2), and a reference to the runtime constant pool (§2.5.5) of the class of the current method."
    "Thus the size of the frame data structure depends only on the implementation of the Java virtual machine, and the memory for these structures can be allocated simultaneously on method invocation."
    "Only one frame, the frame for the executing method, is active at any point in a given thread of control. This frame is referred to as the current frame ..."
    2.6.1 Local Variables
    "Each frame (§2.6) contains an array of variables known as its local variables. The length of the local variable array of a frame is determined at compile-time ..."
    "The Java virtual machine uses local variables to pass parameters on method invocation."

- HotSpot JVM
- JRockit JVM


  • JRockit
  • IBM JVM
  • SUN JVM
  • Open JDK


По Sun/Oracle HotSpot garbage collectors
    - "Memory Management in the Java HotSpot™ Virtual Machine"
    - "Garbage collection-friendly programming"
в Sun/Oracle HotSpot Java 7 два самых продвинутых коллектора - CMS и G1, при старте JVM мы можем выбрать один из них:
    - оригинальная статья о CMS от авторов - "A Generational Mostly-concurrent"
    - оригинальная статья о G1 от авторов - "Garbage-First Garbage Collection"
    - сравнение CMS и G1 - "CMS and G1 Collector in Java 7 Hotspot: Overview, Comparisons and Performance Metrics"
в Sun/Oracle HotSpot Java 7 так же встроенные другие коллекторы, при старте JVM мы можем выбрать один из них:
    - "Tuning Garbage Collection with the 5.0 Java TM Virtual Machine"

Общая по GC
    - GC book
    - gc dict

finalize(), SoftReference/WeakReference/PhantomReference
- Java References (WeakReference, SoftReference, PhatomReference, ReferenceQueue) 
    - Finalizers, Threads, and the Java Memory Model
    - названия-не-знаю

- direct memory (ByteBuffer + Unsafe.?) 

Тесты




--------------------------------------------------------------
примитивные типы данных всегда хранятся в стеке?
- да
+ нет
(локальная переменная метода и статического метода, конструктора, инициализатора и статического инициализатора, аргумент метода и стат метода, конструктора лежат в стеке. Но примитивное поле экземпляра класса (не статическое) лежит в хипе, примитивное поле класса (статическое поле) лежит в PermGen)

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

экземпляры ссылочных типов данных всегда хранятся в хипе?
+ да
- нет
(все, что выделяется по new явно или неявно (enum), хранится в хипе)


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

ссылки на экземпляры ссылочных типов данных могут быть из стека?
+ да
- нет
(да, из локальной переменной)



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

ссылки на экземпляры ссылочных типов данных могут быть из хипа?
+ да
- нет
(да, из поля объекта (не статического поля))

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

ссылки на экземпляры ссылочных типов данных могут быть из PermGen?
+ да
- нет
(да, из поля класса (статического поля))


--------------------------------------------------------------
void f(long N) {
    for (long k = 0; k < N; k++) {
        long tmp = k + 1;
    }
}
Каждый раз входя в тело цикла мы имеем новую переменную tmp никак не связанную с предыдущей, значит на каждую переменную tmp выделяется новая память, значит при достаточно большом N:
- может не хватить памяти и будет выброшено OOM.
- память будет потребляться, но так как мы теряем ссылки на предыдущее значение, то нас выручит GC.
+ у этого метода фиксированное потребление памяти не зависящее от N
--------------------------------------------------------------

void toUC(String str) {
    str.toUpperCase();
}
main() {
    String str = "hello!";
    toUC(str);
    sout(str);
}
распечатает 
- "hello!"
- "HELLO!"

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