Java 虚拟机简单理解
与PC寄存器一样,Java虚拟机栈也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。
1.虚拟机栈的特点“虚拟机栈”描述的是Java方法执行的内存模型:
每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储:局部变量表、操作数栈、动态链接、方法出口等信息。(栈帧我的理解就是一个对象,用来存储信息用)
每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
局部变量表
存放了8种基本数据 类型
对象引用 类型
returnAddress 类型
除64位 long 和 duble 占2个局部空间外,其余的数据类型只占1个。注意,局部变量表所需的内存空间在编译期间完成分配,所以进入某个方法时,这个方法需要在栈桢中分配多大的空间完全是确定的,在方法运行时是不会改变局部变量表的大小的。
3.虚拟机栈出现异常两种情况
如果线程请求的深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常;
如果虚拟机进行动态扩展,而扩展时无法申请到足够的内存,则抛出 Out ...
循环引用是否会被回收
前言见过一个问题说,如果java里的对象出现了循环引用,对象会不会被回收。结论是:会。因为 java 的对象存活算法,使用的是可达性分析算法,而不是引用计算法,java中任何一款GC都没有使用过引用计算法。
示例:
1234567891011public static void main(String[] args) throws IOException { A a = new A(); B b = new B(); a.bb = b; b.aa = a; //a = null; //b = null; System.in.read();}
jvm 手动触发gc
很多时候我们在学习JVM时,往往需要查看JVM的回收日志,查看JVM的相关运行参数,这时候我们可以通过手动触发的形式获取JVM的运行回收情况。
加上参数
-Xms1024m -Xmx1024m -Xmn512m -XX:+PrintGCDetails。
代码1234567891011121314151617public class TestGCRoots01 { private int _10MB = 10 * 1024 * 1024; private byte[] memory = new byte[8 * _10MB]; public static void main(String[] args) { method01(); System.out.println("返回main方法"); System.gc(); System.out.println("第二次GC完成"); } public static void method01() { ...
竟态条件 racing condition
竟态条件 racing condition多个线程读时,线程是安全的。当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。我的理解,竞态条件就是一种情况。
代码示例假设有 A、B 两个线程,调用 add 方法分别传入 1 和 2,理想条件下结果应该是 3。现在出现了不安全的情况,有可能结果不对。add 方法就是临界区,count 就是同一资源。
123456class Counter { protected long count = 0; public void add(long value) { this.count = this.count + value; } }
其实这样一看,说白了,就是要严格控制线程的执行顺序,假设是按A、B的顺序执行来讲,B依赖于A先执行完成,B再执行结果才是正确的,中间不能出现问题,否则如果,中间交叉执行,就有可能发生了竞态条件。
JVM 分代的概念
堆,才有分代的概念。堆,才有分代的概念。堆,才有分代的概念。
分代JVM 将内存分为大致分为三个区域,1.8 前后有区别
为什么要分代
不分代行不行
不分代完全可以,但是分代的唯一理由是为了优化GC性能。怎么优化?如果不进行分代,每次GC都要把整片堆扫一遍来寻找垃圾对象,太慢。分代直接把对象创建到某一个分代区,这样GC就可以针对这一分代区域就行优化,就不费劲了。
年轻代
eden、survivor、from、to
年轻代分三个部分:
Eden 区,即新生对象区,除大对象以外,新生对象都创建在这里。
Survivor 区,即幸存区,该区域又分两个空间s0 和 s1 分别也叫 from 和 to,默认比例8:1。
对象经历的过程
新创建对象,分配到Eden区,除大对象特殊处理。
在 Eden 区经过一次GC后,如果仍存活,移到 Survivor。
在 Survivor 中又经历一次 GC,年龄会增加一岁。
年龄到一定程度,移到老年代。
年轻代使用什么GC算法
是复制算法。
为什么选复制算法?因为:年轻代中的80%以上的对象很快就死亡。所以,在年轻代的垃圾回收算法使用 ...
jvm 的局部变量表
局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。Java中方法的局部变量是放在虚拟机栈的局部变量表里面,形参也算一个。本地变量表,就是局部变量表,只是翻译不同。代码说明
运行时栈帧中存储了以下内容
局部变量
操作数栈
动态链接
返回地址
附加信息
每一个方法的调用开始和结束都是栈的压入(入栈)和弹出(出栈)的过程
12345public static void main(String[] args) { byte[] waste = new byte[6 * 1024 * 1024]; int new_var = 0; System.gc(); }
反编译得到:
1234567891011public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=3, args_size=1 0: ldc #2 ...