jvm内存区域图:
程序计数器
特点:
- 较小的内存空间
- 当前线程所执行的字节码的行号指示器,用于选取下一条需要执行的字节码指令。分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成。
- 线程私有
- 没有规定任何
OutOfMemoryError
情况的内存区域
案例:
iconst
:将常量值进栈
istore
: 将一个数值从操作数栈存储到局部变量表
iload
:压入操作数栈
bipush
:将int ,float,String
常量值推送到栈顶
iadd
: 加
imul
:乘
goto
:跳转
if_icmpne
:比较栈顶两int型数值大小,当结果不等于0时跳转
详情请看:
https://blog.csdn.net/zhangpan19910604/article/details/52254053
https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
java虚拟机栈
特点:
- 线程私有
- java方法执行的时候,会创建一个栈帧
- 异常:StackOverflowError,OutOfMemoryError
栈帧:
- 局部变量表
- 基本数据类型
- 对象引用
- returnAddress
- long,double会占用亮哥局部变量空间(slot)
- 操作数栈
- 动态链接
- 方法出口
StackOverFlowDemo:
/**
* VM Args: -Xss128k
* test stack over flow
* @author shawn
*/
public class StackOverFlowDemo {
private int stackLength = 1;
public void recursion(){
stackLength ++;
recursion();
}
public static void main(String[] args) {
StackOverFlowDemo demo = new StackOverFlowDemo();
try {
demo.recursion();
} catch (Throwable e) {
System.out.println("current stack depth: " + demo.stackLength);
throw e;
}
}
}
/*
output:
current stack depth: 982
Exception in thread "main" java.lang.StackOverflowError
at com.shawn.jvm.StackOverFlowDemo.recursion(StackOverFlowDemo.java:13)
at com.shawn.jvm.StackOverFlowDemo.recursion(StackOverFlowDemo.java:14)
at com.shawn.jvm.StackOverFlowDemo.recursion(StackOverFlowDemo.java:14)
at com.shawn.jvm.StackOverFlowDemo.recursion(StackOverFlowDemo.java:14)
*/
OutOfMemoryDemo:
while(true){
new Thread(()->{
while(true){
}
}).start();
}
运行结果:
unable to create new native thread
本地方法栈:
与虚拟机栈非常相似,区别不过就是虚拟机栈执行的是java方法,而本地方法栈则是执行的native方法。
java堆
特点:
- 线程共享
- 存放的是对象实例以及数组
- GC主要区域
- 三个部分:
- 新生区
- 养老区
- 永久区
逻辑上有三个部分:新生区(young),养老区(Old Tenure),永久区(Perm)java8以后称永久区为元空间
物理上只有两个部分:新生区(young),养老区(Old Tenure),元空间在本地内存中,不在JVM中!
GC的主要区域是young,old。
具体放到垃圾回收那一部分来说明
案例
/**
* VM -Args -Xms6m -Xmx6m -XX:+HeapDumpOnOutOfMemoryError
* @author shawn
*/
public class HeapDemo {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
int i = 0;
try {
while (true){
byte[] bytes = new byte[1024];
list.add(bytes);
i++;
}
} catch (Throwable e) {
long maxMemory = Runtime.getRuntime().maxMemory();
long totalMemory = Runtime.getRuntime().totalMemory();
System.out.println("i = " + i);
System.out.println("maxMemory = " + maxMemory);
System.out.println("totalMemory = " + totalMemory);
throw e;
}
}
}
/*
output:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid19760.hprof ...
Heap dump file created [6065661 bytes in 0.027 secs]
i = 4440
maxMemory = 5767168
totalMemory = 5767168
Exception in thread "main" Exception in thread "Monitor Ctrl-Break" java.lang.OutOfMemoryError: Java heap space
at com.shawn.jvm.HeapDemo.main(HeapDemo.java:17)
*/
方法区
特点:
- 线程共享
- 存储类信息,常量,静态变量,即时编译器后的代码
- 运行时常量池,用于存放各种字面量和符号引用
// -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
public class OomDemo {
static class OOMTest{}
public static void main(String[] args) throws Throwable {
int i = 0; // 模拟计数器
try {
while (true){
i++;
// 不断的加载对象! Spring的 cglib;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMTest.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return method.invoke(o,args);
}
});
enhancer.create();
}
} catch (Throwable e) {
System.out.println("i=>"+i);
e.printStackTrace();
}
}
}
直接内存
/**
* -Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
* @author shawn
*/
public class DirectBufferDemo {
public static void main(String[] args) throws Throwable {
System.out.println("配置的MaxDirectMemorySize"
+ VM.maxDirectMemory()/(double)1024/1024+"MB");
TimeUnit.SECONDS.sleep(2);
// ByteBuffer.allocate(); 分配JVM的堆内存,属于GC管辖
// ByteBuffer.allocateDirect() ; // 分配本地OS内存,不属于GC管辖
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
// java.lang.OutOfMemoryError: Direct buffer memory
}
}
/*
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:694)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at com.shawn.jvm.DirectBufferDemo.main(DirectBufferDemo.java:22)
*/