jvm

73 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

栈(非堆)

存放的是基本类型和引用类型
对象存放在堆中
栈中存放对象的引用地址

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变量的对象可能引用了其他对象,顺藤摸瓜,直到某一个被引用的对象不再引用其他对象,这个链条断裂,不在这个链条上的对象都是垃圾对象

jvm调优的时候,把老年代调小点,eden和survivor调大点,因为朝生夕死的对象尽量被消化在eden和survivor中

内存4G的机器,如果分配3G给内存区域,老年代分2G,根据eden和from/to(survivor)的默认比例8:1:1的情况下,eden会分配800M,from和to均被分配100M,假设大并发的情况下,每秒产生的对象是80M,eden区10秒就会被占满,发生youngGC的情况下可能有80M的对象正在被使用,这个对象会被分配到from区,根据动态年龄判断机制,由于80M>100M*50%,该对象会被直接丢到老年代,这样就会频繁的发生fullGC