jvm随笔记录2-jvm内存(运行时数据区)
上文说到类加载器对class文件进行加载,会将文件加载进jvm的内存中,即运行时数据区
运行时数据区又可细分为 JAVA栈、本地方法栈、程序计数器、堆、方法区(1.8前叫永久代,1.8后叫metaspace,元空间),下面主要写下对这几块区域的理解
1.方法区
主要是用于存放类的静态变量、常量、类信息,比如new一个新的对象,则需要根据方法区中的类信息来创建,方法区是一个逻辑上的抽象概念,实际上jvm来实现这些数据的存放用的是元空间,这个是方法区的具体实现。
2.程序计数器
jvm在执行class文件的内容时(也就是在java栈中对类中方法进行执行的时候),记录的一个执行序号,class文件中的每行代码都有对应的序号,程序计数器就是记录程序已经执行到哪行代码。
3.本地方法栈
存放的java中的一些本地方法,比如Object类中getclass、notify方法
4.java栈
Java栈的有栈帧这种数据结构,而栈帧有以下数据结构:局部变量表、操作数栈、方法出口,根据下面代码来讲解
public class JvmTest { public int caculate(){ int a = 1; int b = 3; int c = a + b; return c; } public static void main(String[] args) { JvmTest test = new JvmTest(); test.caculate(); } }
比如main线程在执行JvmTest类的main方法时,首先将main方法栈帧压入栈中,test作为局部变量放入main栈帧的局部表量表中,在执行到 test.caculate() 方法时,会将caculate方法栈帧压入栈中,这时caculate栈帧的局部变量表则存放的时 a、b、c三个表量,同时这些数据的操作都是在操作数栈中进行操作,比如a=1,会在操作数据栈中将1赋值给局部表量a,在caculate方法执行完之后,caculate栈帧则会进行出栈操作,同理,在main方法执行完之后,main栈帧会出栈。在这一些列的操作中,程序计数器则会记录操作的代码序号。
5.堆
堆中主要存放的时程序运行中创建出来的对象,比如new出来的对象都会存放在堆中。堆的数据结构分为:新生代、老年代,系统默认的内存空间分配为 新生代占堆的1/3,老年代占2/3。新生代的区域又划分为 eden区和两个survivor区(s1区、s1区),eden区占新生代的8/10,s1区和s2区分别各占1/10,新生代的垃圾回收算法是复制算法,老年的的垃圾回收算法是标记整理,eden区的内存被放满之后会执行一次轻GC(也叫minor gc/young gc),会将eden区中存活的对象标记出来,将存活的对象复制到s1区,将垃圾对象清理掉,下次eden区再满的时候,再次进行minor gc,则会将eden区和s1区中存活的对象标记出来,复制到s2区中,清理掉剩余的垃圾对象,如果eden区再满之后,同理,会将eden区和s2区中存活的对象复制到s1区中,而后清理掉剩余的垃圾对象,这种存活的对象由s1复制到s2一次,对象的分代年龄就会加1,同理,s2复制到s1也会增加一次分带年龄,如果分代年龄达到15岁(jvm默认是15,可设置),这个对象就会转移到老年代中,当老年代区内存满了之后会进行一次full gc,这里粗略的描述了一下堆中新生代和老年代内存处理情况,以及什么时候会垃圾回收,后面再详细记录下这块内容。
在上述各结构中,java栈、程序计数器、本地方法栈 是属于线程私有的,而堆和方法区的属于线程间共享的。
上述讲到堆满了之后会进行GC,那么gc是根据什么来判断对象是否可以清理的呢,这里就有一个相关的概念:gc root;当发现堆中的对象的gc root根节点没有时,就会认为这个对象是可以清理。比如栈中的局部表量表就是一个gc root根,当gc root根节点没有时,就会对对象进行清理。
这里同时再记录一下对象的引用关系有如下几种:强引用、软引用、弱引用
强引用:一个变量引用一个对象,具体如下代码,只要时强引用的类型,那么在垃圾回收的时候绝对不会区回收这个对象
public class Test{ public static Person person = new Person(); }
软引用:具体代码如下,就是把Person实例对象用一个“SoftReference”软引用类型的对象包裹起来,此时person变量对Person对象的引用就是软引用了,通常正常情况下垃圾回收时不会回收软引用对象的,但是在发现内存以放不下新的对象,内存都快溢出了,则会对软引用数据进行回收处理,哪怕它被变量引用,但是因为它时软引用,还是会回收掉,使用软引用就表示该对象时可有可无的
public class Test{ public static SoftReference<Person> person = new SoftReference<Person>(new Person);
}
弱引用:具体代码如下,就是把Person实例对象用一个“WeakReference”软引用类型的对象包裹起来,此时person变量对Person对象的引用就是弱引用了,这个弱引用就跟没有引用一样,如果发生垃圾回收,就会把这个对象回收掉
public class Test{ public static WeakReference<Person> person = new WeakReference<Person>(new Person); }
最后记录一下JVM内存相关的几个核心参数信息:
1.-Xms:java堆内存的大小
2.-Xmx:java堆内存的最大大小
3.-Xmn:java堆内存中新生代的大小,扣除新生代之后就是老年代的大小了
4.-XX:PerSize:永久代大小
5.-XX:MaxPerSize:永久代最大大小
6.-Xss:每个线程的大小
7.-XX:SurvivorRatio:新生代中eden区占比,默认8,即eden区占80%,两个survivor区各占10%
jdk1.8以后的版本-XX:PerSize、-XX:MaxPerSize替换成-XX:MetaspaceSize和-XX:MaxMetaspaceSize;如下示例:
-Xms512M -Xmx512M -Xmn256M -Xss1M -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=128M

浙公网安备 33010602011771号