首先栈通俗的来讲就是面向java的,储存的多为基本数据将类型及其值,还有就是一些引用对象的变量,再者就是在堆中的引用地址。
栈是先进后出的。
就好比我们经常听到会有“压栈”这一说,那也就是说,栈好比一个木桶,底部是封闭的,一个java程序进入会先执行main方法,因此main会压进栈的最底层,当然也意味着main方法在最优先执行的同时也是最后一个结束,如果main方法在其子调用方法结束之前就被弹出了,那其子方法的调用的这个逻辑结构就崩塌了,因此程序也不会成立。
当然,就像桶有自己的容量一样,栈的内存也不是无穷无尽的,当main方法上被无限压入子方法的时候就会导致桶本身被撑爆,这就是栈溢出问题出现的原因。
栈内存:主管程序运行,线程同步,生命周期
栈帧:
原图地址:https://space.bilibili.com/95256449?from=search&seid=9695561906625651420
堆
通俗来讲java堆是面向程序员的,储存的是一些new出来的对象,数组,以及一些变量,常量。由于一个JVM只有一个堆,堆要为整个JVM提供服务,因此堆是为所有线程所共享的。堆内存是可以调节的,那既然所有线程都可以访问堆,那自然也会在某一瞬间在堆中产生一些不必要的垃圾,因此堆也是GC回收的重点对象。
其中堆内存还可以细分为三个区域:
- 新生代
- 老年代
- 永久区
结构图:
执行:
同样是自上而下,堆中的新生代储存首先存在的是诞生时间相对较短的对象,然后经过一次轻量GC过后,不会被清洗掉的内容会进入幸存0区,如果幸存0区的内容经过gc后仍然存货,那也会进一步走幸存1区,当然在大部分情况下幸存0和幸存1是动态的。
如果经历过一定数量的GC过后该对象仍然存活,那对象就会因此进入老年代,相对于新生代,老年代的GC不会如此的频繁,但如果老年代的中数据过分的积累,那同样会引发一次重GC,以此来清理堆内存。
最底层的是JVM的永久区,jdk1.6永久区在常量池,1.7后永久区在堆中,在JDK8以后永久区更名为元空间,去永久花,常量池在元空间,GC不会清理元空间,元空间中常驻一些JDK自己需要使用的class和接口。