面试准备 --- Java内存模型(板块划分)

为了春招,系统地复习一下Java相关的知识,应该不会写源码解析,完全是给自己看的,如果足够幸运,有幸进入大厂,重新写下给别人看的

注意点

  • JVM的版本很多,细节多有不同,这里说的是Hotspot VM.

  • 最主要的就是Heap,也就是堆.堆是线程共享的

    • 堆主要分为年轻代(Young)和老年代(Old),常规的默认值是,年轻代:老年代 = 1/4~1/3 ;写下主要是为了防止被问到,其实没什么意义,因为这个比例不同版本都会不同,而且我相信大厂一定会根据自己的业务修改这些参数或者指定自己的虚拟机.
    • 年轻代分为两个部分,三个板块,即"1和Eden区 + 2 个 Survivor区",比例默认值是8:1:1
      • Eden , 也就是伊甸园,有种万物起源的感觉,在JVM中,也就是 刚被创建的对象存放的地方.不过当对象的大小大于一个阀值,就会被放在Old区.这个阀值可以通过参数设置,参数博客再说.
      • 2个Survivor区通常被称为s0,s1,理论上二者是一样大的.翻译过来就是幸存者,其实在JVM中也有这样的意思,当Eden区满的时候,JVM会做Young GC(Minor GC),也就是从Eden中找出还存活的对象,如何判断对象是否还存活,需要另开一个博客说.活下来的对象,就要进入s0或者s1(二者都可以),如果选择了s0,所有活着的对象就会放在s0中,如果s0满了,剩下的对象会被放在old区,然后会将Eden区清空,当Eden区再满的时候,会将s0和Eden区中活着的对象放在s1中,(同样的,放不下就放在old区),然后清空Eden和s0,然后反复进行.如果经过多次Minor GC还活着的对象,就会被放在old区,这个反复也是有默认值的,是15次,但还是上面说的关于默认值的问题.
    • 进入old区有多种方式(比如s0或s1满了,又或者反复多次minor gc还存活),但无论以何种方式进入,都是同样对待的.old区域的对象会被认为是长寿的.而old区只有进行FULL GC才会被清理,但FULL GC其实是很不好的,进行Full GC时,所有正在进行的工作都要停止,厉害的虚拟机也体现在对于高并发情况也可以很久做一次FULL GC.
  • 虚拟机栈,线程私有

    • 虚拟机栈主要描述了Java方法执行时的内存模型,每个方法在执行的同时都会创建一个栈帧,用于存放局部变量表,操作数栈,动态链接,方法出口等信息,每一个方法从调用到执行完成的过程,就是对应栈帧入栈出栈的过程
    • 虚拟机栈有一个常见的异常,即使StackOverFlowError,这个异常大家可能在使用递归时遇见的,因为递归是方法内调用方法,如果递归层次太深,所有的方法栈帧都无法出栈,自然就会栈溢出,这也是我不喜欢使用递归的原因.
  • 方法区 , 方法区是线程共享的,用于存放已被虚拟机加载的类信息(Class对象),常量(常量池内),静态变量,即时编译器编译后的代码等数据.

  • 永久代–元空间,方法区的实现.

    • 永久代在1.8就被移除了,代替的是元空间,其实从1.7就开始了,很多永久代的东西在1.7就开始移到堆中,但是还保存这这块区域,到了1.8彻底移除了.但是还是要知道的.
    • 永久代和元空间是方法区的实现,这个怎么说,就是方法区是那么一块区域,但是也是需要回收内存,所以就使用堆空间的分代收集扩展到了方法区,然后就将实现回收后的方法区称为永久代,但这仅限于HotSpot,因为其他虚拟机都不存在永久代这个概念.
    • 虽然垃圾回收在方法区中很少见,但是还是有的,主要是随常量池和类型的卸载.
    • 永久代和元空间在很多方面还是相似的,主要区别就是元空间不在虚拟机内,而是在本地内存中
  • 运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用,我们可以接触到的就是String类的intern方法,可以将一个String字面量作为常量放入常量池中,常量池作为方法区的一部分,也受到方法区大小的限制,当满了以后会抛出OOM.

  • 剩下还有程序计数器和本地方法栈,都是很难接触到的部分,提一句就行了.

猜你喜欢

转载自blog.csdn.net/qq_36865108/article/details/86656347
今日推荐