JVM notes

November 3, 2017


  • A class file consists of bytecode and a symbol table
  • There are two kinds of types: primitives and references
  • Reference types can be either a dynamically allocated class instance or an array.
  • There is no way to distinguish primitive types within bytecode except for the operands used to manipulate them. Each operand has a different version depending on the type: e.g.: iadd, ladd, fadd and dadd are addition operands for int, long, float and double.
  • Integral, signed numbers use two’s-component notation
  • Primitive types memory:
    • byte, 8-bit, from 2^7 to 2^7 - 1
    • short, 16-bit, from 2^15 to 2^15 - 1
    • int, 32-bit, from 2^31 to 2^31 - 1
    • long, 64-bit, from 2^65 to 2^65 - 1
  • char is the only integral type that is unsigned and it represents a Unicode code point encoded in UTF-16
  • There is a primitive type called returnAddress, whose value can be pointers to the opcodes of JVM instructions.
  • The pc (program counter) register contains the address of the current JVM instruction being executed. There is one pc per thread.
  • Every thread contains a stack (created when the thread itself is created)
  • Every stack stores frames
  • There is a limited to the number of frames per stack, that may be tunable depending on the JVM implementation.
  • If the limit of frames is reached, an StackOverflow exception is thrown.
  • When a new thread is created but there is no enough memory to create its initial stack, an OutOfMemoryError is thrown.
  • Heap is the runtime data area where objects are allocated. It is shared by all threads and is created when the JVM is started up.
    • If a computation requires more heap than available OutOfMemoryError is thrown.
  • The method area is where the runtime constant pool, fields information and functions’ code is stored, in a per-class basis. Shared by all threads.
  • The runtime constant pool is a per-class representation of the class’ constant_pool table.
    • Allocated in the method area.
  • A frame stores partial results, performs dynamic linking, returns values from methods and dispatch exceptions.
    • Created everytime a method is invoked, destroyed when the method terminates or throws.
  • Local variables is an array of the variables of a frame (method)
    • Size determined at compile time
    • Can hold boolean, int, byte, char, short, float, reference and returnAddress.
    • long and double are represented by two local variables
    • Referenced by index
    • Method parameters are assigned to local variables
    • For class methods, starting at 0
    • For isntance methods, starting at 1 (0 would be a reference to this)
  • Operand stack is a LIFO stack where operands are pushed or pop by bytecode instructions.
  • Constructors are named <init> in the bytecode
  • Class initializers are named <clinit>.
  • When an exception is thrown and is not handled in the current method, local variables and operand stack are discarded, the current frame is poped from the stack, and the exception rethrown in the context of the invoker’s frame.
  • If the exception propagates unhandled after reaching the last frame, its thread is terminated.
  • JVM instructions are one byte opcodes
  • Ignorning exceptions, the inner loop of a JVM looks like this:
do {
  atomically calc pc and fetch opcode at pc;
  if (operands)
    fetch operands;
  execute action for opcode;
} while( there is more to do);
  • If operands are bigger than one byte, they are saved in big-endian order.
  • Internally, the JVM does not handle booleans. Instead, the compiler emits instructions that operate on ints.
  • load and store instructions push and pop data into and from the stack. The parameter for the instruction is the index of a local variable. e.g. iload 3 pushes the 4th local variable in the frame to the stack.
  • Comparisons between long, float and double yield an integer, which is then tested using one of the int-specific instructions and the branching is performed.

© 2017 | Powered by Hugo ♥ | Art by Clip Art ETC