你是否有喜欢的明星,喜欢的偶像,一个人喜欢某个人,那这个人身上一定有他所欣赏的东西,我喜欢五月天,五月天有一颗少年心,并且他的歌词总能唱到我的心坎里,世界那么大,如果拥有一个和你相同想法的人,那么就不会那么孤单,就算他不认识你。所以,如果一颗心感到冰冷,那么可能是你没有找到一个可以温暖你内心的人,我相信只要永不止步,总有一天你能找到你所热爱的人,你所热爱的事。
啰嗦完了,今天开始说说java的内存模型
1 程序计数器
2 本地方法栈
3 java虚拟机栈
4 堆
5 元空间
其实就是这五块区域
具体介绍一下
1 程序计数器 记录每一步字节码的行号 ,线程私有,保证多个线程过来执行顺序不错乱
2 本地方法栈 用为native方法执行时占用的空间,就是JNI方法的调用,但是如果大量使用,也就是丧失了java的跨平台性
3 java 虚拟机栈
虚拟机栈又细分为
1)局部变量表
2)操作栈
3)动态连接
4) 方法返回地址
我们平常说的栈的结构其实指的是操作栈的结构,他结构就像一个枪的弹夹,最后压入的子弹最先发射(弹夹放子弹是从弹夹的头部放入),那这几个都干嘛的
局部变量表会存储方法的参数和局部变量,向它里面放数据的字节码指令是istore
通过代码来理解一下
public int stack() {
int x = 10;
int y = 11;
int z = x + y;
return z;
}
他的字节码是
public int stack();
Code:
0: bipush 10 //将10压入操作栈
2: istore_1 //并将10保存到局部变量表istore_1中
3: bipush 11 //将11压入操作栈
5: istore_2 //并将11保存到局部变量表istore_2中
6: iload_1 //将局部变脸表1压入操作栈
7: iload_2 //将局部变脸表2压入操作栈
8: iadd //把栈中值取出来放到cpu中计算,并压回栈顶
9: istore_3 //把栈顶的值弹出来放到局部表量表3
10: iload_3 //局部表量表3压入操作栈
11: ireturn //返回栈顶元素值
@return
通过这个执行过程,就能够透彻的了解了,方法的执行其实就是压栈和出栈的过程,同时也注意到,里面出现了局部变量表1,2,3,其实局部变量表也有结构,他的结构就像一个抽屉。
动态链接是每个方法在常量池中的动态引用,而方法返回地址就是执行ireturn,返回命令的地方
4 堆 heap
堆是jvm里面的重要人物,从OOM就可以看出来,他主要就是存储对象,他的结构是啥呢,
它分为新生代区,老年代区,新生代又分为Edgn区,和Survivor区,Survivor又分为s0和s1区
那他们是如果工作的
创建对象的时候,会给对象分配内存,这时候如果对象大于Edgn区的存储空间,那么就放到老年代区,如果不大于就放到Edgn区,如果Edgn区满了,就会触发youngGc,没有被引用就会方法Survivor区,那放到他的哪块空间呢,会放到没有使用的s空间,然后把使用的那块空间清楚,之后交换位置,如果ygc后占用的空间大于Survivor区的最大空间,那么就放到老年代,那互相交换的那部分会一直交换吗?不回,有一个最大次数,15次,如果交换次数大于15次,那就把Survivor区的存储放到老年代区,如果老年代放不下了,那就会触发FullGC,如果FullGc后老年代还放不下,那就OOM了。
5 元空间
jdk7到8有一个变化,就是移除了永久代,他是直接分配到内存的,包含类原信息,静态字段等。
说完jvm的内存结构再说说GC算法
描述堆内结构的时候说了YGC与FullGC,那他是怎么GC的?关键就是判断一个对象有没有用,每个对象都有一个引用,我们只需要判断这个对象有没有引用就可以了,现在主流的使用使用可达性分析法,以前有使用引用计数法,关于这一部分比较复杂,下次再整理