How Memory Works
Programs store values in memory and use addresses to find those values. Data structures organize those values so common operations require fewer moves, comparisons, or allocations.
An address identifies a location in an address space; it does not guarantee that the same amount of physical RAM is installed. A 32-bit address space can represent at most distinct byte addresses (4 GiB), while a 64-bit address space can represent far more. Operating systems, hardware, permissions, and available physical memory limit what a process can actually use. Think of memory as numbered byte locations. An array stores adjacent elements, so the address of an element can be calculated from its start address and index. A linked list stores nodes wherever space is available and follows references from one node to the next.
| Power of 2 | Size |
|---|---|
| 2 | |
| 4 | |
| 8 | |
| 16 | |
| 32 | |
| 64 | |
| 128 | |
| 256 | |
| 512 | |
| 1024 | |
| 2048 | |
| 4096 | |
| 8192 | |
| 16,384 | |
| 32,768 | |
| 65,536 |
Powers of two are useful because binary address calculations and capacity growth naturally use them. For example, bytes and bytes.
Common Java value types
| Data types | Java keyword or wrapper | Memory value | Java value | Explanation |
|---|---|---|---|---|
| Boolean | boolean or Boolean | language-dependent | true or false | Boolean is a reference type; object layout is not one bit |
| Byte (whole number) | byte or Byte | 1 byte (8 bits) | -128 to 127 | 8 bits signed = up to |
| Short Integer | short or Short | 2 bytes (16 bits) | -32,768 to 32767 | 16 bits signed = up to |
| Character (UTF-16 code unit) | char or Character | 2 bytes for char | 0 to 65,535 | A Unicode code point may require one or two UTF-16 code units |
| Integer (whole number) | int or Integer | 4 bytes (32 bits) | -2,147,483,648 to 2,147,483,647 | 32 bits signed = up to |
| Floating number | float or Float | 4 bytes | about 6 to 7 decimal digits | IEEE 754 binary32 approximation |
| Long (long integer whole number) | long or Long | 8 bytes (64 bits) | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | 64 bits signed = up to |
| Double (double precision floating number) | double or Double | 8 bytes | about 15 to 16 decimal digits | IEEE 754 binary64 approximation |
Primitive sizes describe the value representation, not necessarily the full memory consumed by an object. Object headers, references, alignment, and the garbage collector add runtime overhead.
Common value types by language
boolean flag = true; // JVM-dependent size, true to false
byte small = 1; // 1 byte, -128 to 127
short medium = 100; // 2 bytes, -32,768 to 32,767
int whole = 1000; // 4 bytes, -2,147,483,648 to 2,147,483,647
long large = 100000L; // 8 bytes, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
float ratio = 0.5f; // 4 bytes, about -3.4e38 to 3.4e38
double precise = 0.5; // 8 bytes, about -1.8e308 to 1.8e308
char letter = 'A'; // 2 bytes, 0 to 65,535 UTF-16 code units
Boolean flagObject = Boolean.TRUE; // wrapper object, true to false; total size runtime-dependent
Byte smallObject = Byte.valueOf((byte) 1); // 1-byte value, -128 to 127; object overhead runtime-dependent
Short mediumObject = Short.valueOf((short) 100); // 2-byte value, -32,768 to 32,767; object overhead runtime-dependent
Integer wholeObject = Integer.valueOf(1000); // 4-byte value, -2,147,483,648 to 2,147,483,647; object overhead runtime-dependent
Long largeObject = Long.valueOf(100000L); // 8-byte value, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807; object overhead runtime-dependent
Float ratioObject = Float.valueOf(0.5f); // 4-byte value, about -3.4e38 to 3.4e38; object overhead runtime-dependent
Double preciseObject = Double.valueOf(0.5); // 8-byte value, about -1.8e308 to 1.8e308; object overhead runtime-dependent
Character letterObject = Character.valueOf('A'); // 2-byte value, 0 to 65,535 UTF-16 code units; object overhead runtime-dependent
String textObject = "value"; // object, implementation-dependent size; not a numeric wrapper#include <stdbool.h>
#include <stdint.h>
bool flag = true; // 1 byte, false to true
int8_t small = 1; // 1 byte, -128 to 127
int16_t medium = 100; // 2 bytes, -32,768 to 32,767
int32_t whole = 1000; // 4 bytes, -2,147,483,648 to 2,147,483,647
int64_t large = 100000; // 8 bytes, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
float ratio = 0.5f; // 4 bytes, about -3.4e38 to 3.4e38
double precise = 0.5; // 8 bytes, about -1.8e308 to 1.8e308
unsigned char letter = 'A'; // 1 byte, 0 to 255
flag: bool = True # runtime-dependent size, False to True
small: int = 1 # runtime-dependent size, unbounded integer
whole: int = 1000 # runtime-dependent size, unbounded integer
ratio: float = 0.5 # usually 24 bytes, about -1.8e308 to 1.8e308
precise: float = 0.5 # usually 24 bytes, about -1.8e308 to 1.8e308
text: str = "value" # runtime-dependent size, no numeric rangelet flag: bool = true; // 1 byte, false to true
let small: i8 = 1; // 1 byte, -128 to 127
let medium: i16 = 100; // 2 bytes, -32,768 to 32,767
let whole: i32 = 1000; // 4 bytes, -2,147,483,648 to 2,147,483,647
let large: i64 = 100000; // 8 bytes, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
let ratio: f32 = 0.5; // 4 bytes, about -3.4e38 to 3.4e38
let precise: f64 = 0.5; // 8 bytes, about -1.8e308 to 1.8e308
let letter: char = 'A'; // 4 bytes, 0 to 1,114,111 Unicode scalar values
const flag: boolean = true; // runtime-dependent size, false to true
const small: number = 1; // usually 8 bytes, safe integer -9,007,199,254,740,991 to 9,007,199,254,740,991
const whole: number = 1000; // usually 8 bytes, safe integer -9,007,199,254,740,991 to 9,007,199,254,740,991
const large: bigint = 100000n; // runtime-dependent size, arbitrary signed integer
const ratio: number = 0.5; // usually 8 bytes, about -1.8e308 to 1.8e308
const text: string = "value"; // runtime-dependent size, no numeric range
var flag bool = true // 1 byte, false to true
var small int8 = 1 // 1 byte, -128 to 127
var medium int16 = 100 // 2 bytes, -32,768 to 32,767
var whole int32 = 1000 // 4 bytes, -2,147,483,648 to 2,147,483,647
var large int64 = 100000 // 8 bytes, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
var ratio float32 = 0.5 // 4 bytes, about -3.4e38 to 3.4e38
var precise float64 = 0.5 // 8 bytes, about -1.8e308 to 1.8e308
var letter rune = 'A' // 4 bytes, 0 to 1,114,111 Unicode scalar valuesAllocation and access
These examples declare a variable and allocate an array with space for a fixed number of elements:
// Declare an integer variable.
int i;
// Allocate an array with ten integer elements.
int[] array = new int[10];int i;
int array[10];i: int
array = [0] * 10let i: i32;
let mut array = [0i32; 10];let i: number;
let array: number[] = new Array(10);var i int
var array [10]intTo access the variable and store something:
i = 32;
array[9] = 32;i = 32;
array[9] = 32;i = 32
array[9] = 32i = 32;
array[9] = 32;i = 32;
array[9] = 32;i = 32
array[9] = 32array[9] is the tenth element because these examples index arrays from zero. Out-of-bounds access
varies by language: Java raises an exception, Rust panics, and C behavior is undefined.