JVM内存结构如下:
主要包括了下面几个部分:
程序计数器(线程私有)
存放着当前线程所执行的字节码的行号指示器
栈(线程私有)
每个方法被执行的时候都会创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息,每一个方法被调用直到执行完的过程就对应了一个栈帧在JVM中从入栈到出栈的过程。
本地方法栈(线程私有)
与上面的栈相似,不同的是它是为执行native方法用的
方法区(永久代,对应JDK1.8中元空间,线程共享)
存放JVM加载的类信息、常量,静态变量,即编译器编译后的代码等数据
堆(线程共享)
JVM中内存最大的一块区域,在JVM启动的时候创建,用于存放几乎是所有对象的实例
GC算法针对的是堆:
JVM中的垃圾收集器回收的对象主要就是堆中的部分,因为每一个栈帧分配多少内存在类结构确定的情况下就是已知的,所以内存分配和回收比较容易。而方法区中的部分回收的性价比比较低,因为这一区域存放的都是一些常量以及类信息,经常会被用到,所以在JDK8中把这部分迁移到了本地内存来做。
而堆就不同,堆存放的是一些对象实例,很多都是一些朝生夕死的对象,一次回收就能回收大部分的空间,所以GC回收算法针对的主要是堆区域。
JVM调优的一些见解:
1.GC调优的目的只有一个,尽量让对象在年轻代就回收掉,不要让它进入老年代
2.大的年轻代会增加每次minor GC的时间,但是会延长GC的周期,而且大的年轻代说明老年代相对较小,会导致更频繁的Full GC
3.通过参数设置GC调优一般是最后的手段,多数GC的问题一般都是代码的问题,应该首先考虑优化自己的代码.
***jvm是如何调用gc进行垃圾回收的***
堆内存分为三部分:永久存储区+新生区+养老区
新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生区又分为两部分:伊甸区(Eden space)和幸存者区(Survivor pace),所有的类都是在伊甸区被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。那如果1区也满了呢?再移动到养老区。