JVM结构图
类加载器把字节码文件(.class)文件加载JVM虚拟机中的过程
以上是Java虚拟机的结构,和编译加载流程。
JVM内存管理
Java栈区:
作用: 它存放的是Java方法执行时的所有的数据
组成: 由栈帧组成,一个栈帧代表一个方法的执行
Java栈帧:
每个方法从调用到执行完成就对应一个栈帧,在虚拟机中入栈到出栈。(局部变量、栈操作数、动态连接、方法出口)
本地方法栈:
本地方法栈专门为native方法服务的
方法区:
储存被虚拟机加载的类的信息、常量、静态变量、即时编译器编译后等数据, 特此强调方法区是永远占据内存的。
Java堆区:
作用: 所有通过new创建的对象的内存都在堆中分配
特点: 是虚拟机中最大的一块内存
堆区内存
新的内存放入新生代区,当再次创建对内存的时候,上一次创建的新生代内存,会被移动到老生代区,(以此类推)当新生代、老生代内存不足时会抛出异常触发GC回收
JVM垃圾回收机制
1、引用记数算法:(现在已经淘汰)
当对象被引用时,计数器加1,当计数器为0时被视为垃圾,但是当两个对象互相引用的时候,那么就会造成永远回收不掉。
2、垃圾收集算法(目前用到的算法)
从GC-ROOT根节点一直循环遍历,会判断出哪些是可达和不达(就是有没有被引用),不可达的节点被称为垃圾对象,会被回收掉
引用的类型:
强引用: 哪怕内存不足,都不会回收强引用对象
软引用: 在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。
弱引用: 无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。
虚引用: 虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,在 JDK1.2 之后,用 PhantomReference 类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。
引用队列: 引用队列可以与软引用、弱引用以及虚引用一起配合使用,当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去。程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。
弱引用的创建:
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj)
obj = null;
wf.get();
弱引用的创建 和使用
创建强引用Object对象,然后创建一个弱引用,然后在把obj制成null, 那么obj就只有一个弱引用了, 通过wf.get()获取真正的引用, 用的时候要先判断是不是空,因为弱引用会被回收
垃圾回收算法
1、标记 -清除算法
直接遍历GC-ROOT根节点,A引用路由到了了C对象, 在扫描的时候发现B没有被引用,被标记为垃圾,在垃圾回收的时候会清楚B。 优点是:不需要对象的移动,仅对不存活的对象进行处理,在存活对象多的情况下比较高效,但是缺点是会造成垃圾碎片,比利于后期对象内存分配。
2、复制算法
遍历GC-ROOT根集合,会把A对象和C对象复制到内存空闲的区域,复制完毕以后,会把之前的内存清空。有点:当存活对象比较少时极为高效,内存不碎片化缺点:内存交换空间用来对象的移动。存活对象多不高效
3、标记-整理算法
同理,也是遍历GC-ROOT根集合,只是在标记算法的基础之上加以改动,在扫描的的时候会把不存活B对象和内存删除掉,会把存活对象向左空闲位置移动,更新空闲指针。解决了内存碎片问题,但是对对象进行了移动,成本也会变高。所以三种各有利弊,在虚拟机中结合使用
总结:在内存中存活对象比较少,虚拟机会用复制算法, 而存活对象比较多 虚拟机会用标记整理算法,和标记算法
触发回收机制:
1、Java虚拟机无法再为新的对象分配内存空间了
2、手动调用System.gc()(强烈不推荐,手动调用不是即时回收)
3、低优先级的GC线程,被运行时就会执行GC
Android 虚拟机介绍
Dalvik 虚拟机寄存于寄存器,效率高
Dalvik 与 ART的不同
JIT技术是每次运行的时候把字节码转换成机器码,每次退出应用在进入怒就会重新编译一遍,效率低。
ART技术采用AOT预编译技术,AOT技术:是在应用安装的时候,就会把字节码转换成机器码存起来。以后启动的时候用的是本地的机器码,所以启动更快。