1. 对于JVM的理解
JVM将内存主要划分为:程序计数器、JAVA虚拟机栈、本地方法栈、堆、方法区等几个部分。
1) 程序计数器
是线程私有的区域,每个线程需要有个计数器记录当前执行到那个指令。如果当前线程是在执行java方法,那么这个计数器记录的是正在执行的虚拟机字节码指令地址。如果执行的是native方法,则计数器的值为空。
2) java虚拟机栈
也是线程私有的。其生命周期与线程相同。里面存放的元素叫栈帧。栈帧里面存放的是一个函数的上下文,具体存放的是执行函数的一些数据。执行引擎每调用一个函数,就为这个函数创建一个栈帧,并加入虚拟机栈。这个区域可能抛出两个异常:一种stackOverFlowError(栈溢出):函数反复递归。另一种是OutOfMemoryError,当虚拟机栈可以动态扩展时,如果无法申请足够多的内存区域就会抛出该异常。
3) 本地方法栈
与虚拟机栈的作用很类似,区别在于与,虚拟机栈为执行Java代码方法服务,而本地方法栈是为native方法服务。也会抛出虚拟机栈的异常。
4) java堆
是虚拟机中最大的一块内存。它是所有线程共享的内存区域。几乎所有的实例对象都在这块区域中放置。堆是垃圾收集器管理的主要区域。现在的垃圾收集器基本上都采用的分代收集算法,所有堆都可以细分为新生代老年代。当堆无法再扩展时,就会抛出OutOfMemoryError。
5) 方法区
存放的是类信息、常量、静态变量等。各个线程共享区域。这块区域回收主要是针对常量池回收,值得注意的是JDK1.7已经把常量池转移到堆里面了。
2. 使JVM关闭的几个条件
JVM的关闭意味着将停止系统中所有的任务,可以由其自动关闭也可以主动触发。
1)所有的非守护都已经运行结束
2)调用了System.exit方法。
3)杀死JVM进程
4)通过系统平台发送关闭信号(比如按Ctrl+C)
3. java中会存在内存泄漏吗?
会;存在无用但可达的对象,这些对象不能被GC回收,导致耗费内存资源。 (无用但可达:对象被实例化,并且被其他对象引用,但是其本身没有被赋值)
4. GC是什么?为什么要用它?
GC是垃圾收集的意思(Gabage Collection),忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。
5. 垃圾收集算法
1)标记-清除算法:通过可达性分析,将可回收的对象进行标记,标记后再统一回收所有被标记的对象。
2个不足点:效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量的不连续的内存碎片。
2)复制算法: 将内存分为两块大小相同的区域,当一块区域使用完的时候,将这块区域活着的对象复制到另一块区域。每次只对半个区域进行垃圾回收,也没有内存碎片。
1个不足点:需要牺牲一半的内存空间。
3)标记整理算法:先标记需要回收的对象,然后把所有活着的对象移动到内存的另一端。这样的好处是避免了内存碎片。
4)分代收集算法:主要思路是根据对象存活生命周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代。新生代中,对象的存活率比较低,所以选用复制算法,老年代中对象存活率高且没有额外的空间对它进行分配,所以使用“标记-清除”或“标记-整理”算法进行回收。
6. 垃圾回收机制
用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间。需要注意的是:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身。
7. 关于JVM调优参数解释
1) -Xms:堆内存最小值
2) -Xmx:堆内存最大值
3) -Xss:设置每个线程可使用的内存大小。在相同物理内存下,减小这个值能生成更多的线程。当然操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
4) -Xmn: 用来设置堆内新生代的大小。通过这个值我们也可以得到老年代的大小:-Xmx减去-Xmn
5) -XX:MetaspaceSize和-XX:MaxMetaspaceSize:分别用来设置永久代的最小大小和最大大小,本地元空间Metaspace
8. 关于JVM调优工具
9. 造成FULL GC的方式
1) 直接调用System.gc:此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI(Java远程方法调用)调用System.gc。
2) 旧生代空间不足:旧生代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出错误:java.lang.OutOfMemoryError: Java heap space 。为避免以上两种状况引起的FullGC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
3) Permanet Generation空间满了:Permanet Generation中存放的为一些class的信息等,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出错误信息:java.lang.OutOfMemoryError: PermGen space 。为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC。
4) 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
5) 由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代可用内存不足(老年代可用内存小于该对象)
10. 关于OOM
OOM一般可分为三种:permgen OOM ,heap OOM, stack overflow
1)permgen OOM :这个主要是由于加载的类太多,或者反射的类太多,还有调用 String.intend(jdk7之前)也会造成这个问题
2)heap OOM:主要是因为一些无用对象没有及时释放造成的,检查代码加上 heap dump 去分析
3)stack overflow :这个主要是由于调用层数,或者递归深度太大造成的