The Java Virtual Machine defines various run-time 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.
程序计数器
记录下一条JVM指令的地址
线程私有,每个线程都有自己的程序计数器
不会存在内存溢出
# Each Java Virtual Machine thread has its own pc (program counter) register.
# If that method is not native
# the pc register contains the address of the Java Virtual Machine instruction currently being executed.
# If the method currently being executed by the thread is native
# the value of the Java Virtual Machine's pc register is undefined.
虚拟机栈
每个线程运行时所需要的内存,每个线程对应一个虚拟机栈
// 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.
垃圾回收不涉及栈内存
方法内的局部变量是线程私有的,不会有线程安全问题
public class Demo {
// 多个线程同时执行此方法
static void m1() {
int x = 0; // 每个线程都会有自己的虚拟机栈, x是线程私有的, 线程安全
for(int i = 0; i < 5000; i++){
x++;
}
System.out.println(x);
}
// 这个不是线程安全的,因为是从外面传过来的,外面也可以访问sb指向的对象
// 可以使用StringBuffer代替
static void m2(StringBuilder sb){
sb.append(1);
sb.append(2);
System.out.println(sb.toString());
}
// 这个不是线程安全的,其他线程有可能拿到sb引用的对象
// 方法执行完,sb变量(栈中)会被释放,但是指向的对象在堆中
// 过段时间此对象还没有变量指向, GC才会清理此对象
static StringBuilder m3(){
StringBuilder sb = new StringBuilder();
sb.append(1);
sb.append(2);
return sb;
}
}
类的static变量是对多个线程共享的,会有线程安全问题
本地方法栈
调用native方法时,给native方法提供的内存空间
堆
(程序计数器,虚拟机栈,本地方法栈)都是线程私有的
(堆和方法区)都是线程共享的
# The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads.
# The heap is the run-time data area from which memory for all class instances and arrays is allocated.
堆中有垃圾回收机制,堆中不再被引用的对象都会被释放
OutOfMemory(又称之为OOM)
java.lang.OutOfMemoryError:Java heap space(堆内存溢出)
java.lang.OutOfMemoryError:PermGen space(永久代\方法区溢出)
jps # 显示Java进程
jmap -heap pid # 显示这一时刻指定Java进程的堆空间情况
jmap -dump:format=b,file=fileName pid # 生成dump文件,保存了某一时刻JVM堆中对象使用情况
jmap -dump:live,format=b,file=c:\dump\heap.hprof pid # live指只转储堆中的活动对象
还可以使用jvisualvm工具(jdk8之后需要额外下载)
jmap命令使用详解
生成和查看dump文件
生成HeapDump
方法区
方法区所有线程共享
# The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads.
它存储每个类的结构,如(运行时常量池,字段和方法数据),以及(方法和构造函数的代码),
包括在(类和实例初始化以及接口初始化)中使用的特殊方法.
# It stores per-class structures such as the run-time 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.
尽管方法区在逻辑上是堆的一部分,但简单的实现可以选择不进行垃圾收集或压缩.
# Although the method area is logically part of the heap, simple implementations may
# choose not to either garbage collect or compact it.
方法区是规范
永久代和元空间都是它的实现
HotSpotJDK7及之前,永久代,在堆中
HotSpotJDK8及之后,元空间,移除到本地内存中了,常量池的StringTable一直都在堆中
javap -v Test.class # 显示class文件中的信息
javap -c Test.class # 对class文件进行反编译