本文已参与「新人创作礼」活动,一起开启掘金创作之路。
栈(非堆)
存放的是基本类型和引用类型
对象存放在堆中
栈中存放对象的引用地址
JVM一直是java知识里面进阶阶段的重要部分,如果希望在java领域研究的更深入,则JVM则是如论如何也避开不了的话题,关于jvm的基本结构,我们看一张图片
图片中栈,本地方法栈,程序计数器都被标记为同一种颜色,因为他们都是线程私有的.
栈中都有什么.
这里有两个方法(main和cal),我都标记了栈帧,栈就是由一系列的栈帧组成,每一次方法调用创建一个帧,并压栈.栈的特点就是先进后出,所以main方法在栈底,cal方法在栈顶
程序计数器的概念
当前线程执行的字节码行号指示器,看一下图片就一目了然,它跟字节码执行引擎有关系
本地方法栈
调用本地方法时分配的一块内存区域,比如调用线程的start()方法,start()方法的底层是C,这就意味着当时写本地方法的意图就是与其他系统进行调用,现在基本上已经不用这么搞了,因为有了rpc等更吊炸天的操作
方法区
看我的JVMCalculate类中的initnum和JVMUser都存放在方法区,它们分别是静态变量和常量,类信息也会存放到方法区,你可能会有疑问JVMUser是一个对象,对象应该存放在堆中啊,是的,针对对象,方法区存放的是它的内存地址
瞅一眼啥是堆
堆是GC的主要区域
堆的结构有点复杂,分成eden,survivor和老年代(元代)
新创建的对象都会被分配都eden(伊甸园->亚当和夏娃待过的地方),经过折腾后,那些老不死的对象最终会到达老年代(分代年龄默认是15)
分代年龄==15------>老年代
继续分析堆内存
说道堆就会说道GC(垃圾回收),一般情况下新创建的对象都会放到eden中,如果eden区内存满了就会触发youngGC,如果对象没有用(垃圾对象),就会被清除,如果该对象正在被线程引用,就会将对象分配到survivor区.
survivor内存区满就会触发GC,from区和to区通过复制算法将不死的对象来回搬运,搬运一次,分代年龄+1,分代年龄达到15的对象被扔到老年代.
老年代的内存区域如果满了就会触发fullGC了
如何找出垃圾对象->可达性分析算法
通过GCROOT对象作为起点,你可能不知道什么是GCROOT对象,JVMCalculate和JVMUser都可以作为GCROOT,它们分别是本地变量和静态变量.
GCROOT变量的对象可能引用了其他对象,顺藤摸瓜,直到某一个被引用的对象不再引用其他对象,这个链条断裂,不在这个链条上的对象都是垃圾对象