1、JVM虚拟机内存结构是什么?
堆、方法区、程序计数器、本地方法栈,虚拟机栈
2、里面分别的都存了什么东西?
堆所有线程共享在虚拟机启动的时候创建 一般用来存储对象实例并分配内存,如果堆中没有内存完成实例分配,而且堆也无法扩展的时候就会报OutOfMemoryError异常
方法区也是被线程共享的,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,方法区无法满足内存分配需求时也会抛出OutOfMemoryError异常
本地方法栈为虚拟机使用到的Native方法服务 虚拟机栈为java内部方法服务
程序计数器用来作为当前线程所执行的字节码的行号指示器,字节码解释器工作的时候就是靠改变这个计数器的值来选择下一条需要执行的字节码指令,这个是线程私有的,如果执行的是native方法,这个计数器的值则为空(Undifined)
Java虚拟机栈是执行java方法时的内存模型,每个方法执行的时候都会创建一个栈帧用来存储局部变量表、操作数栈、动态链接、方法出口等信息、如果线程请求的深度超过虚拟机允许的深度就抛出StackOverflowError异常,如果扩展时无法申请到足够的内存就会抛出OutOfMemoryError
3、常见垃圾收集器都有哪些?都有什么优缺点?
Serial收集器
单线程收集、在新生代对象不大的时候很适合使用(一两百M的话垃圾收集几十毫秒到一百多毫秒),省去了线程切换带来的开销、使用复制算法、在新生代快满的时候把存活的对象复制到老年代
Serial Old收集器(Serial老年代版本)
跟Serial收集器一样,不过用来处理老年代垃圾收集,采用的算法是标记-整理算法
ParNew收集器
(Serial的多线程版,在CPU少的时候性能不一定会比Serial好,但是优势是可以与CMS收集器搭配使用,这是一个用来收集新生代的垃圾收集器采用复制算法
Parallel Scavenge收集器 jdk1.4
与ParNew最大的区别是可以设置吞吐量 = 代码运行时间/(代码运行时间+垃圾收集时间)
(新生代收集器、复制算法、多线程、控制吞吐量)
Parallel Old收集器
(Parallel Scavenge老年代版本),可以和Parallel Scavenge搭配使用,不然的话只能Parallel Scavenge与Serial Old搭配,那样的话老年代收集会很慢
CMS收集器
是一种以获取最短回收停顿时间为目标的收集器,使用标记清除算法 不过它的过程比较复杂,分为4个步骤
初始标记、并发标记、重新标记、并发清除.重新标记是为了修正并发标记时因为用户程序继续运行而产生变动的那一部分对象的标记
缺点是对CPU资源很敏感,无法处理浮动垃圾、标记清除算法带来的内存碎片化问题,要在Full GC的时候碎片合并,等待时间会变长
G1收集器
优势
1、可以在垃圾收集的时候同时执行程序
2、可以独立管理整个GC堆,采用不同的方式处理新生代对象和熬过多轮GC的对象
3、标记整理算法,不会在G1运作期间产生空间碎片,有利于程序长期运行,减少GC次数
4、可预测的停顿,可以让用户指定在多少时间内消耗在垃圾收集的时间为多少毫秒
可以追踪每个Region,优先回收价值最大的Region
一般新生代使用复制算法比较好,老年代因为存活率高并且没有空间做担保用标记-整理 xc/标记-清理算法