最近面试的头大,好久没面试了,发现自己这些基础一点的东西都忘得差不多了,面试只能说到个大概,面不过有点小气人。
一、jdk1.7和jdk1.8的模型
下图是java1.7的内存结构
下图是java1.8内存结构
上面2图分别是jdk1.7与jdk1.8的内存模型
jdk1.8的时候jvm有很大的改进:使用元空间(mate space)取代了永久代。虽然元空间逻辑上仍然可以视为方法区的一种实现,但是在jdk1.8的jvm里面却没有给予方法去单独的一块内存区域了。
在jdk1.7的版本开始,已经开始了一部分去永久代的工作。比如字符串常量池迁移到堆内存中。而1.8则更进一步,把方法区的运行时常量池等信息全部迁移到了本地内存(native memory)之中,因此jdk1.8的jvm内存划分如上图java1.8内存结构
二、分区解析
1.程序计数器
程序计数器是一块较小的内存空间,可以看作当前线程执行的字节码的行号指示器。
如果线程执行的是一个java方法,计数器记录的是正在执行的虚拟机字节码指令的地址;
如果线程执行的是一个Native方法,这个计数器值则为空。
2.java虚拟机栈
线程私有的,每个线程对应一个java虚拟机栈,其生命周期与线程共同进退。每个java方法在杯调用时就会创建一个栈帧,并将该方法入栈,一旦调用完成就出栈。
当所有栈帧都出栈后,线程也就完成了实名。在局部变量表存储了8中基本数据类型,对象引用类型和returnAddress的类型。
3.本地方法栈
与虚拟机栈所发挥的作用类似,区别在于java虚拟机时java方法服务的,而本地方法栈则是为虚拟机栈使用到的native方法服务的。
4.java堆
java堆时java虚拟机所管理的内存中最大的一块,java堆时被所有线程共享的一块内存区域,在虚拟机启动时创建,此区域唯一的目的就是存放对象实例。java堆时内存回收的主要区域(GC堆)。从内存回收的角度看,java堆可细分成为新生代和老年代。
堆内存如上分为:
老年代(堆的1/3)
新生代(堆的2/3)
Eden区(新生代的8/10)
Suivival 0区(新生代的1/10)
Suivival 1区(新生代的1/10)
5.元数据区
元数据区取代了1.7版本的永久代。
元数据区和永久代本质上都是方法区的实现。
方法去存放虚拟机加载的类信息,静态变量,常量等数据。
6.直接内存
直接内存并不是java虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。
jdk1.4引入了NIO,他可以使用Native函数库直接分配堆外内存。
三、java堆的新生代、老年代、永久代的关系
如上,新生代分为三个区域、一个eden区和2个Suivival区,它们之间的比例为(8:1:1),这个比例时可以修改的。
通常情况下,对象主要分配在新生代的eden区,少数情况下可能会分配到老年代中。
java虚拟机每次使用新生代中的eden区和一块Suivival(From),经过一次Minor GC之后,将Eden和Suivival(From)中还存活的对象一次性复制到另一块Suivival(To)空间上(这里使用复制算法进行GC),最后清理掉刚才的Eden区和Suivival(From)区空间。
将此时复制过来的Suivival(To)区内存活的对象年龄设置为1,以后这些对象在Suivival(To)区中熬过一次GC,他们的年龄就+1,直到某个对象的年龄(默认15)时,就会将这个对象移动到老年代中。
在新生代中进行GC的时,有可能遇到另一款Suivival(To)区没有足够空间存放上一次新生代收集下来的存活对象,这些对象将直接通过分配担保机制进入老年代;
Eden区
eden区位于java堆中的新生代区内,时新生对象分配内存的地方,由于堆时所有线程共享的,因此在堆上分配内存需要加锁。而Sun JDK为了提升效率,会为每个新建线程的eden上分配一块独立的空间由该线程独享,这块空间成为TLAB(Thread Local Allocation Buffer)。在TLAB上分配内存不需要加锁,因此JVM在给线程中的对象分配内存时,会尽量在TLAB上分配。如果对象过大或TLAB用完,则仍然在堆上进行分配。如果Eden区内存用完了,则会进行一次Minor GC(young GC)。
Suivival From 和 Survival To
Survival区与Eden区同属于java堆中的新生代区内。Survival区有两块,一块成为From区,另一块时To区,这两个区是相对的,在发生了一次Minor GC之后,From区和To区会互换。
在发生Minor GC时,Eden区和Survival From区内还存活的对象复制到Surval To区内,并清除Eden和Surval From区,此时使用标记复制算法
处理执行GC。
Survival To区会把一些存活足够久的对象移至老年代。
老年代
老年代存放的都是存活时间比较久的,空间较大的对象,因此老年代使用标记整理算法
。
当老年代容量满的时候,会触发一次Major GC (Full GC),回收老年代内不在被使用的对象资源。
总结:
1.Minor GC(young GC)是发生在新生代中的垃圾收集,采用标记复制算法
。
2.新生代中每次使用的空间不会超过90%,主要用于存放新的的对象。
3.Minor GC每次收集后,Eden区和Survival From区都会被清空。
4.老年代中使用Full GC(老年代只会执行Major GC,但是在老年代执行Major GC之前,会先在新生代执行一次Minor GC,所以这里说是Full GC),老年代采用标记清除算法
【未完,准备将担保机制一起放进来,时间关系,先放个担保机制的链接】
担保机制:https://blog.csdn.net/kavito/article/details/82292035
参考:https://blog.csdn.net/s674334235/article/details/103106482
参考:https://blog.csdn.net/weixin_43847987/article/details/102294286
参考:https://blog.csdn.net/qq_19734597/article/details/80958817