jvm_堆栈永久区详细讲解

第一块是堆,第二块是垃圾收集器,这就是咱们要讲的两块

堆是JAVA中非常关键非常核心的一部分,因为JAVA实例化出来的一些对象,都是存在内存堆空间中的,几乎所有的

对象都放在其中,且JAVA堆完全是由垃圾回收系统自动管理的,不是像C语言要手动写一个命令GC的那种东西,

堆是自动管理的,是通过垃圾回收系统自动化管理的,通过垃圾回收机制,我们会把这个对象自动去清理,不需要

像其他语言比如C显示的是释放,然后根据垃圾回收机制的不同,注意我的PPT写了,JAVA堆中可能有不同的结构,

总的区域是一定的,最为常见的就是将整个堆分为新生代和老年代这两个大块,一大块就是叫做新生代,一大块

就是叫做老年代,这是面试问的非常多的,JAVA堆知道是怎么划分的吗,JAVA新生代存放新生产出来的对象,老年代

就存放已经生产很久的对象,新生代就是年龄不大的对象,老年代就是年纪很大的对象,具体它是怎样划分的呢,

新生代又分成3个区域,分为eden区,s0区,s1区,s0和s1也被称为from和to区域,他们是两块大小相等并且可以

互换角色的空间,他们指的是s0和s1区
其实在我们的JAVA中堆就这么一块空间,称之为JAVA的heap,它分为两大块,整体上分为2大块,第一大块叫做

新生代,第二大块叫做老年代,这是最外面最宏观的一次划分,然后关于新生代这块,有分为3块区域,首先第一块

叫做eden区,为什么叫做eden呢,这个翻译过来叫做伊甸园,所以我们给他取个名字叫eden,其实我们的JAVA对象

刚刚实例化出来的时候,刚new出来的时候,这个对象是放在eden区的,然后经过1次垃圾回收机制,经过1次GC就是、

垃圾收集器,就是这个对象看有没有用了,比如这个代码写完以后,只要他经历过一次GC的话,user对象就会从Eden

区域出来,出来不是直接到老年代,它就会到s0和s1区域,或者叫做from和to,s0和s1区域他们两个是什么概念呢,

这两块区域是两块大小相等,并且是可以相互转换角色的空间,为什么要这么去设计呢,说明我们JAVA的对象,

user经历过1次GC以后,会到s0或者是s1区,就是这对象可能是到s0区,也可能是s1区,就不可能是这个对象既在s0

区也在s1区,说明就在我们这个JAVA中对象要么都存在s0区,要么都存在s1区,就是如果一个对象存在s0区,那s1区

就不会有任何对象,如果有对象存在s1区,s0区就没有任何对象,所以他们就是两个大小相等,并且可以想换转换

角色的空间,为什么我们的JAVA虚拟机是这么去设置的呢,在老年代里就无所谓了,老年代就是经历过多少次GC以后

比如我们JAVA里面默认是经过15次GC以后,它就会从新生代晋升到老年代,但是我们唯一不理解的就是s0和s1咱们

的JAVA虚拟机为什么设计成这种形式,s0和s1这一块可能不理解,那根据我们刚才所描述的概念.

大多数情况下,我们的对象首先分配在eden区,在一次新生代回收之后,也就是垃圾回收之后,如果还存活着,如果

程序还用着这个user,那么这个对象就会进入到s0或者s1区,因为不可能两个都有,每次经历GC操作的时候,

如果我们的对象一直存活,那它的年龄就加1,也就是第一次回收了,发现还被程序使用者,那就加1,第2次GC再加1,

一直加到15的时候OK,无论是s0区也好,还是s1区也好,这个对象就会直接扔到老年代这块,在这里简单跟大家说一下

垃圾收集算法,其中有一个非常经典的算法,就是复制的算法,其核心就是将内存空间分为两块,每次只能使用

其中的一块,在垃圾回收的时候,将正在使用的内存中的存留的对象复制到未被使用的内存块中去,之后去清除

之前正在使用的内存块中所有的对象,反复去交换两个内存的角色,完成垃圾收集,你该明白新生代和老年代是一个

什么样的概念了,它就是一个交替呼唤的角色,为什么要这么去设计呢,咱们单独来分析新生代的s0和s1这两个区间

他们是两块大小相等并且可以呼唤角色的空间,我们这边叫做新生代,其实在我们的JAVA里边,你写程序写了很多

代码,你在应用系统里边,很多对象就用了一次,或者调用的时候就用了一次,它不可能常驻在我们的内存中的,

所以对一用完了就马上被回收,所以就在新生代的时候,垃圾回收太频繁了,并且需要垃圾回收的对象也太多了,

比如现在我们的程序创建了100个Object,在这100个对象中,可能仅仅百分之1或者百分之2,这是比较常见的,

就是100个对象里面只有1个或者2个存活在15次以上,存活15次以上才会存放在老年代,一般的JAVA对象经历了

几次的GC之后,都会被我们的垃圾回收机制给回收掉,并且在我们的新生代产生对象实在是太频繁,老年代产生的

GC要少于新生代很多很多,因为你的这个对象已经经历了15次的淘汰了,还没有被回收,老年代的对象在我们老年代

的周期,你的这个JAVA程序或者servlet,tomcat的启动到关闭的整个生命周期内这个对象始终都在用着,但是

绝大部分的对象在新生代生产消亡,分配空间,经历几次GC之后就消亡了,我们有n个对象放在s0区,然后我们采用的

是复制的算法,比如我们这里有100个对象,有40个对象还,咱们的垃圾回收机制怎么做呢,这40个还存活的对象

copy到s1去,剩下就不管了,清空这块s0区,下次我们就用我们的s1区,下次我们GC的时候,还有20个还存活着,

然后再把s1的20个再copy回来,可能就是一个递归了,其实就是源源不断有新的对象产出,然后由老的对象经历过

几次GC被回收的情况,这个就是一个概念性的问题,为什么要使用复制算法,就是因为新生代太频繁了,

对象的产生和被垃圾回收走太频繁了,所以我们要有一种复制的算法,然后去清空空间,这两个角色相互交替的

转换
其实就是一个概念性的问题,其实真正工作的时候用的不是特别的多,复制肯定不会包括eden区,eden区

就包括对象,对象经历过一次GC之后肯定从eden区出来,到咱们的s0或者s1
JAVA栈就是咱们线程的一块私有空间,每一个线程你去实例创建的时候会有一个Thread,你会发现栈和我们的

线程是息息相关的,调用多少次,比如深度什么的,后期咱们看代码就知道了,栈咱们也分三个部分,局部变量表,

操作数栈,帧数据区,这三个东西比较拗口.

1. 局部变量表: 用于报错函数的参数及局部变量

2. 操作数栈: 主要保存计算过程的中间结果,代码写一个冒泡排序,你写代码的时候就有一个临时转换的角色,

临时变量的转换角色

3. 帧数据区: 也是用于处理一些异常,函数的返回结果或者出现异常,必须有一个异常处理表,其实局部变量表和

帧数据区差不多,一个是函数报错参数的存储,还有一个是返回结果报错存储的,涉及到了一些常量的指针,因为很少

有人读一下JAVA虚拟机源码,因为肯定是用C写的,只要存一些打印的信息就行了,然后咱们临时变量的存储呢,是存

在操作数栈这个东西里,那咱们最简单明了的一句话,栈存的都是一些临时变量,方法中肯定会写一行一行的代码,

然后变量相互的去转换,具体内部可能是通过这3分区域去进行维护的,你可以不用了解的非常详细,这块你有兴趣

你可以去查查资料,一般不会问你栈太核心的,如果问了你可以反问他,你可以说记得栈里面分了局部变量表,

操作数栈,帧数据区这三个部分,那我可能知道操作数栈写代码临时中间变量的转换,局部变量表和帧数据区是打印

一些方法的入口,出口的一些异常,了解到这里就行了
JAVA方法区和堆一样,方法区是一块所有线程共享的内存区域,静态的,类的字段,方法,方法区的大小可以决定

系统可以保存多少个类,如果系统定义的类太多,就会导致方法区溢出,你可能写了一个非常大的一块代码,你做了

一个非常复杂的垂直化的系统,里面400、500个类,然后你给Tomcat的方法区几百个M,Tomcat就会报方法区的内存

溢出,它会有这个提示,它就是永久区.虚拟机同样也会提示这种错误,现在我们其实不用面对这种问题,

因为我们现在都是很多面多微服务,都是面向分布式的服务,一个服务不可能放一个非常复杂的业务系统,所以这个

异常我们可以忽略,方法区就和我们创建多少个类直接关联.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值