初探JVM
Posted lynnk1ng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初探JVM相关的知识,希望对你有一定的参考价值。
JVM:Java虚拟机,有自己的处理器、堆栈、寄存器、指令系统,Java程序只需要生成在该虚拟机上运行的代码就可以在多平台上运行(屏蔽了操作系统相关的平台信息)。
Java编译器编译.java文件 -> .class文件,Java虚拟机加载运行.class文件。
JVM运行时数据区域:
方法区:加载的类结构信息,常量值、字段、方法信息、静态变量
Java虚拟机栈:属于线程私有,方法调用的状态,局部变量、参数、返回值、运算结果等
本地方法栈:可能会调用本地C栈,虚拟机会保持Java栈不变,不再在线程的Java栈中压入新的帧,虚拟机只是简单地动态连接并直接调用指定的本地方法
Java堆:对象实例,分配内存(GC主战场)
程序计数器:保证程序能够持续的运行(不会抛OutOfMemoryException),JVM的多线程是通过轮流切换、分配处理器来实现的,要保证切回来时继续往下执行。
GC:垃圾回收机制
对象引用:
强引用:新建的对象为强引用时,GC绝对不会回收该类对象,宁愿抛OutOfMemoryException也不会回收
弱引用:不管内存是否足够,GC只要执行就一定会回收该类对象
软引用:当内存不够时,GC会尝试回收该类对象,如果回收后还是没有足够的内存,就会抛OutOfMemoryException
虚引用:如果一个对象仅持有虚引用,任何时候都可能会被GC回收,但是回收时会发一个系统通知(用来判断GC在执行了)
垃圾标记算法:
引用计数算法:每个对象都有一个引用计数器,当对象每被引用一次就+1,引用失效一次就-1,计数=0表示可以被回收。
Obj o1 = new Obj();Obj o2 = o1;o1=null;此时o1计数仍为1,无法解决对象之间的相互引用。
根搜索算法:通过一系列的“GC Roots”的对象作为根节点,往下搜索组成引用链(递归),如果目标对象与根对象有引用链可达时,不会回收,如果没有引用链不可达,则判定可回收。
垃圾收集算法:
标记-清除算法:根据根搜索算法标记可被回收的对象,然后对被标记为垃圾的对象进行回收。
缺陷:JVM会停止应用程序的运行并开启GC线程进行根搜索标记,需要遍历整个堆内存,效率很低,由于清理出来的空间是不连续的,不好给数组对象分配连续的内存空间,会产生大量内存碎片。
复制算法:先把内存一分为二,每次只使用其中一个区域,垃圾收集时,会把存活的对象全部连续的复制到另一个区域中,再对之前的区域全部回收。
缺陷:内存开销少一半。
标记-压缩算法:将存活的对象压缩、排列到内存的一端,对端边界以外的内存进行回收。
分代收集算法:Java堆内存存在的对象生命周期有很大的差别,有的很短有的很长,分代算法就是根据对象的生命周期长短将对象放到不同的周期区域中。Eden:From:To 8:1:1
在对象被创建时,会放到新生代Eden中,当Eden内存耗尽时,会执行一次GC将所有存活的对象复制到From中,然后继续消耗Eden内存,下次执行GC,将Eden中所有存活的对象和From中的对象复制到To中,循环往复Eden+From->To / Eden+To->From,达到JVM内置的阀值后,会认为仍然存活的对象的生命周期很长,会放到老年代中,直到老年代中内存耗尽时GC会执行标记-压缩算法回收垃圾。
内存泄漏/溢出/抖动
内存泄漏:一个不再被程序使用的对象或变量依旧存活在内存中无法被回收。内存泄漏越多,程序可使用的内存就越少。
内存溢出:程序申请内存时,没有足够的内存可供使用。
内存抖动:通常指在短时间内发生了多次内存的分配和释放,主要原因就是短时间内频繁创建对象,为了应对这种情况,JVM会频繁触发GC,而GC执行时其他线程会被挂起,频繁GC,就会导致比如UI在绘制时会超过16ms一帧,造成画面卡顿等。
以上是关于初探JVM的主要内容,如果未能解决你的问题,请参考以下文章