一、JVM
1.1 JVM内存模型?( 即JVM 的组成部分及其作用):
参考:https://zhuanlan.zhihu.com/p/101495810
1.2 JVM 的运行时数据区?
程序计数器: 每个线程都有独立的程序计数器,用来在线程切换后能恢复到正确的执行位置,各条线程之间的计数器互不影响,独立存储。所以它是一个“线程私有”的内存区域。此内存区域是唯一一个在JVM规范中没有规定任何OutOfMemoryError情况的区域;
虚拟机栈: 在JVM规范中,对这个区域规定了两种异常情况:如果线程请求的栈深度大于虚拟机允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,在扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常;
本地方法栈: 本地方法栈和虚拟机栈所发挥的作用是很相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。Sun HotSpot 直接就把本地方法栈和虚拟机栈合二为一。本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常;
堆: Heap是OOM故障最主要的发源地,它存储着几乎所有的实例对象,堆由垃圾收集器自动回收,堆区由各子线程共享使用;通常情况下,它占用的空间是所有内存区域中最大的,但如果无节制地创建大量对象,也容易消耗完所有的空间;堆的内存空间既可以固定大小,也可运行时动态地调整,通过参数-Xms设定初始值、-Xmx设定最大值;
方法区: 在使用到CGLib对类进行增强时,增强的类越多,就需要越大的方法区类存储动态生成的Class信息,当存放方法区数据的内存溢出时,会报OutOfMemoryError异常;
2.1 JVM概述:
在 Java 中, 根据堆中对象的存活周期将堆内存分为新生代和老年代,新生代默认空间占堆空间的1/3,老年代占2/3
HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to),默认比例为8:1:1,为啥默认会是这个比例,接下来我们会聊到。当有新的对象时,新创建的对象都会被分配到Eden区(一些大对象特殊处理,如果对象特别大,直接进入老年代),当Eden区内存不够的时候,会触发一次MinorGC。这些对象经过第一次Minor GC后,如果仍然存活,将会被移到formSurvivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中
后面Eden满进行Minor GC时,在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域(复制)。经过这次GC后,Eden区和From区已经被清空(清空)。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”(交换)。不管怎样,都会保证名为To的Survivor区域是空的。
每次在form到to都存活的对象,年龄就加1,当年龄达到15时,升级为老年代,大对象会直接进入老年代。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。
Minor GC:简单理解就是发生在年轻代的GC,MinorGC采用复制算法。
Major GC的触发条件:Major GC又称为Full GC。当年老代空间不够用的时候,虚拟机会使用“标记—清除”或者“标记—整理”算法清理出连续的内存空间,分配对象使用。
2.2 JVM 中一次完整的 GC 流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的jvm 参数
对象诞生即新生代->eden,在进行minor gc过程中,如果依旧存活,移动到from,变成Survivor,进行标记代数,如此检查一定次数后,晋升为老年代。
① 年轻代中的GC
HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1,为啥默认会是这个比例,接下来我们会聊到。一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。
因为年轻代中的对象基本都是朝生夕死的(80%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。
在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
② 一个对象的这一辈子
我是一个普通的java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后被回收。
③ 有关年轻代的JVM参数
1)-XX:NewSize和-XX:MaxNewSize
用于设置年轻代的大小,建议设为整个堆大小的1/3或者1/4,两个值设为一样大。
2)-XX:SurvivorRatio
用于设置Eden和其中一个Survivor的比值,这个值也比较重要。
3)-XX:+PrintTenuringDistribution
这个参数用于显示每次Minor GC时Survivor区中各个年龄段的对象的大小。
4)-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold
用于设置晋升到老年代的对象年龄的最小值和最大值,每个对象在坚持过一次Minor GC之后,年龄就加1。
2.3 JVM 调优参数(总结)
2.31 -Xmx、-Xms:设置最大堆内存,设置最小堆内存:
最大堆指的是新生代和老年代的大小之和的最大值;
JVM会试图将系统内存尽可能限制在-Xms中,当内存实际使用量触及到-Xms大小时,会触及到-Xms大小时,会触发Full GC;如果-Xms值比较大时,系统运行初期减少GC的次数和耗时;
2.32 -XX:NewSize和-XX:MaxNewSize:
用于设置年轻代的大小,建议设为整个堆大小的1/3或者1/4,两个值设为一样大。
hot Spot:-XX:NewSize 新生代初始大小 和 -XX:MaxNewSize;设置一个较大的新生代会减少老年代的大小;
2.33 -XX:SurvivorRatio和-XX:NewRatio:
-XX:SurvivorRatio:用于设置Eden和其中一个Survivor的比值,这个值也比较重要。
-XX:NewRatio 设置新生代与老年代比例=老年代/新声代
2.34 -XX:InitialTenuringThreshold和-XX:MaxTenuringThreshold:
用于设置晋升到老年代的对象年龄的最小值和最大值,每个对象在坚持过一次Minor GC之后,年龄就加1。
2.35 -XX:PermSize和-XX:MaxPermSize:
设置持久代
不属于堆的一部分;
持久代的大小直接决定了系统可以支持多少个类定义和多少常量;
-XX:PermSize 设置持久代的初始大小;
-XX:MaxPermSize
2.36 -XX:+PrintTenuringDistribution:
这个参数用于显示每次Minor GC时Survivor区中各个年龄段的对象的大小。
2.37 下图有关GC分配:
【2】Minor GC 和 Major GC(Full GC)
堆内存在大的结构上分为:年轻代和年老代。其中年轻代又分为Eden区和Survivor区。Survivor区又分为两个相等的区域,一个是fromspace区,另外一个是tospace区。年轻代内存=Eden+其中一个Survivor区,也就是说两个Survivor区,虚拟机只使用了其中一个。
Minor GC:简单理解就是发生在年轻代的GC。
Minor GC的触发条件为:当产生一个新对象,新对象优先在Eden区分配。如果Eden区放不下这个对象,虚拟机会使用复制算法发生一次Minor GC,清除掉无用对象,同时将存活对象移动到Survivor的其中一个区(fromspace区或者tospace区)。虚拟机会给每个对象定义一个对象年龄(Age)计数器,对象在Survivor区中每“熬过”一次GC,年龄就会+1。待到年龄到达一定岁数(默认是15岁),虚拟机就会将对象移动到年老代。如果新生对象在Eden区无法分配空间时,此时发生Minor GC。发生MinorGC,对象会从Eden区进入Survivor区,如果Survivor区放不下从Eden区过来的对象时,此时会使用分配担保机制将对象直接移动到年老代。
Major GC的触发条件:Major GC又称为Full GC。当年老代空间不够用的时候,虚拟机会使用“标记—清除”或者“标记—整理”算法清理出连续的内存空间,分配对象使用。
3. 栈和队列是什么、有什么区别?栈堆有什么区别?
4. 双亲委派模型
5. 类装载的执行过程
6. 怎么判断对象是否可以被回收?
7. Java中都有哪些引用类型?
8. JVM 有哪些垃圾回收算法?
详细参考:https://www.cnblogs.com/cjsblog/p/9851699.html