本文共 1584 字,大约阅读时间需要 5 分钟。
栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间。
- 局部变量表:方法中定义的局部变量以及方法的参数存放在这张表中 局部变量表中的变量不可直接使用,如需要使用的话,必须通过相关指令将其加载至操作数栈中作为操作数使用。
- 操作数栈:以压栈和出栈的方式存储操作数的
- 动态链接:每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态 连接(Dynamic Linking)
- 比如private List = List(虚拟机装载的时候还不知道子类的类型,只有运行的时候才知道)
- 方法返回地址:当一个方法开始执行后,只有两种方式可以退出,一种是遇到方法返回的字节码指令;一种是遇见异常,并且这个异常没有在方法体内得到处理。
栈指向堆:
- 如果在栈帧中有一个变量,类型为引用类型,比如
- Object obj=new Object(),这时候就是典型的栈中元素指向堆中的 对象
方法区向堆:
- 方法区中会存放静态变量,常量等数据。如果是下面这种情况,就是典型的方法区中元素指向堆中的对象。
- private static Object obj=new Object();
Java对象内存布
- 对象头
- Mar Word:一系列标志位(哈希码、分代年龄、锁状态标志等)64
- Class Pointer:指向对象对应的类元数据的内存地址64
- Length(数组对象特有)4
- 实例数据
- 对齐填充
jvm内存模型(通常探讨的是方法区 和堆,因为在jvm虚拟机创建时就存在)
- 区别于java内存模型,通常是一个主内存,一个工作内存,同步问题
内存模型
- 一块是非堆区,一块是堆区
- 堆区分为两大块,一个是Old区,一个是Young区。
- 对象特别大直接进入老年代
- 经过15次Minor GC后还存活进入老年代
- Young区分为两大块,一个是Survivor区(S0+S1),一块是Eden区。 Eden:S0:S1=8:1:1 (1:1相同才能相互复制)
- S0和S1一样大,也可以叫From和To
要點:
- 前提:大多数对象是“朝生夕死”(存多点再一次gc时带走多点,所以设置8),生命周期比较短
- Eden区相对连续了,不会因为少量的存活的对象,而造成空间碎片
- Survivor有可能形成空间碎片导致存活对象放不下【S区能够相抵连续】
- 永远保证S0,S1的某个为空能够解决空间碎片的问题【10%的空间浪费了】Eden:S0S:S1=8:1:1
- S0或S1万一不够怎办【跟老年代借点空间,担保机制】
- 另外:
- Young GC【包含Eden,S区】:Minor GC
- Old GC:Major GC,MajorGC通常会伴随着MinorGC,也就意味着会触发FUll GC
- Young+Old:Full GC
- Full GC:STW尽可能减少Full GC的频率
- 尽量减少GC频率
- 实在不行尽可能减少Full GC(允许一定范围内的Young GC)
- 每一次GC,对象的分代年龄都会+1
溢出
-
堆内存溢出:不断创建实例:Exception in thread “http-nio-8080-exec-2” java.lang.OutOfMemoryError: GC overhead limit exceeded
-
方法区内存溢出:添加类信息:ava.lang.OutOfMemoryError: Metaspace at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_191] at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_191]
-
虚拟机栈:StackOverflowError
转载地址:http://ribwz.baihongyu.com/