#3.2 方法区方法区主要的作用是存放类的元数据信息,常量和静态变量···等 。当它存储的信息过大时,会在无法满足内存分配时报错 。
#3.3 虚拟机栈和虚拟机堆一句话便是:栈管运行,堆管存储 。则虚拟机栈负责运行代码,而虚拟机堆负责存储数据 。
#3.3.1 虚拟机栈的概念它是Java方法执行的内存模型 。里面会对局部变量,动态链表,方法出口,栈的操作(入栈和出栈)进行存储,且线程独享 。同时如果我们听到局部变量表,那也是在说虚拟机栈
public class Person{int a = 1;public void doSomething(){int b = 2;}}
#3.3.2 虚拟机栈存在的异常如果线程请求的栈的深度大于虚拟机栈的最大深度,就会报 StackOverflowError (这种错误经常出现在递归中) 。Java虚拟机也可以动态扩展,但随着扩展会不断地申请内存,当无法申请足够内存时就会报错 OutOfMemoryError 。
#3.3.3 虚拟机栈的生命周期对于栈来说,不存在垃圾回收 。只要程序运行结束,栈的空间自然就会释放了 。栈的生命周期和所处的线程是一致的 。
这里补充一句:8种基本类型的变量+对象的引用变量+实例方法都是在栈里面分配内存 。
#3.3.4 虚拟机栈的执行我们经常说的栈帧数据,说白了在JVM中叫栈帧,放到Java中其实就是方法,它也是存放在栈中的 。
栈中的数据都是以栈帧的格式存在,它是一个关于方法和运行期数据的数据集 。比如我们执行一个方法a,就会对应产生一个栈帧A1,然后A1会被压入栈中 。同理方法b会有一个B1,方法c会有一个C1,等到这个线程执行完毕后,栈会先弹出C1,后B1,A1 。它是一个先进后出,后进先出原则 。
#3.3.5 局部变量的复用局部变量表用于存放方法参数和方法内部所定义的局部变量 。它的容量是以Slot为最小单位,一个slot可以存放32位以内的数据类型 。
虚拟机通过索引定位的方式使用局部变量表,范围为[0,局部变量表的slot的数量] 。方法中的参数就会按一定顺序排列在这个局部变量表中,至于怎么排的我们可以先不关心 。而为了节省栈帧空间,这些slot是可以复用的,当方法执行位置超过了某个变量,那么这个变量的slot可以被其它变量复用 。当然如果需要复用,那我们的垃圾回收自然就不会去动这些内存 。
#3.3.6 虚拟机堆的概念JVM内存会划分为堆内存和非堆内存,堆内存中也会划分为年轻代和老年代,而非堆内存则为永久代 。年轻代又会分为Eden和Survivor区 。Survivor也会分为FromPlace和ToPlace,toPlace的survivor区域是空的 。Eden,FromPlace和ToPlace的默认占比为 8:1:1 。当然这个东西其实也可以通过一个 -XX:+
UsePSAdaptiveSurvivorSizePolicy 参数来根据生成对象的速率动态调整
堆内存中存放的是对象,垃圾收集就是收集这些对象然后交给GC算法进行回收 。非堆内存其实我们已经说过了,就是方法区 。在1.8中已经移除永久代,替代品是一个元空间(MetaSpace),最大区别是metaSpace是不存在于JVM中的,它使用的是本地内存 。并有两个参数
MetaspaceSize:初始化元空间大小,控制发生GCMaxMetaspaceSize:限制元空间大小上限,防止占用过多物理内存 。
移除的原因可以大致了解一下:融合HotSpot JVM和JRockit VM而做出的改变,因为JRockit是没有永久代的,不过这也间接性地解决了永久代的OOM问题 。
#3.3.7 Eden年轻代的介绍当我们new一个对象后,会先放到Eden划分出来的一块作为存储空间的内存,但是我们知道对堆内存是线程共享的,所以有可能会出现两个对象共用一个内存的情况 。这里JVM的处理是每个线程都会预先申请好一块连续的内存空间并规定了对象存放的位置,而如果空间不足会再申请多块内存空间 。这个操作我们会称作TLAB,有兴趣可以了解一下 。
当Eden空间满了之后,会触发一个叫做Minor GC(就是一个发生在年轻代的GC)的操作,存活下来的对象移动到Survivor0区 。Survivor0区满后触发 Minor GC,就会将存活对象移动到Survivor1区,此时还会把from和to两个指针交换,这样保证了一段时间内总有一个survivor区为空且to所指向的survivor区为空 。经过多次的 Minor GC后仍然存活的对象(这里的存活判断是15次,对应到虚拟机参数为 -XX:MaxTenuringThreshold。为什么是15,因为HotSpot会在对象投中的标记字段里记录年龄,分配到的空间仅有4位,所以最多只能记录到15)会移动到老年代 。老年代是存储长期存活的对象的,占满时就会触发我们最常听说的Full GC,期间会停止所有线程等待GC的完成 。所以对于响应要求高的应用应该尽量去减少发生Full GC从而避免响应超时的问题 。
推荐阅读
- 二维码的升级版「三维码」你使用过吗?
- 保证健康的宝贵食物你掌握几种
- 开车那么久,你知道该如何保养爱车吗?
- 平板支撑有多厉害?坚持做一个月你就知道了
- 如果你正准备换发型,别错过这30款
- 蚊子最爱叮什么血型的人,你知道吗?
- 揠苗助长的意思和寓意 拔苗助长告诉我们什么道理
- 见男友的小tips是什么梗 见男友的小tips
- 中考成绩怎么查?
- 小叶紫檀|木质界的帝王之木,你了解多少?