java堆内存分配垃圾回收

mac2025-04-06  12

堆内存划分

java堆内存划分为新生代,老年代。一般jvm默认情况下新生代占用堆空间的1/3,老年代占用堆空间的2/3. 新生代又分为Eden区,from survivor区,to survivor区,默认情况Eden区占用新生代的8/10,from survivor 和to survivor各自占用1/10.from survivor 和to survivor位置不是固定,它们经常是来回变化交换名字。

虚拟机默认划分了堆的空间内存范围,但是其实是可以人为配置的,下面界面配置堆内存的参数:

-Xms20m -Xmx20m 设置堆大小内存空间,一般情况为了防止jvm不断调整内存大小,浪费不必要的性能,通常都将最大最小的内存空间值设置一样。-Xmn10M 设置堆空间新生代的大小,这样新生代和老年代的占用比列就不一定是默认的了-XX:SurvivorRatio=8 设置Eden占用新生代大小为8份

java对象内存分配及回收策略

Eden区: 一般情况下java对象在新生代的Eden区,当Eden区没有足够的内存空间,虚拟机将发起一次MinorGC.Survivor区: 在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。Old区: java分配的大对象一般直接存放到老年代中,不经过Eden区,大对象一般是指占用连续分配内存空间的数组,大对象的大小是可以配置。Old区:长期存活的对象将被存储到老年代,这也是为啥被叫老年代的原因吧。当虚拟机执行过一次MinorGC仍然存活的对象且且能被Survivor区容纳时,则该对象的生命计数器加1,当超过15次(默认值)则会从Survivor移动到Old区。(还有一个内存分配担保机制待补充)old区: 动态对象年龄判定,虚拟机并不是永远要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象的大小的总和大于Survivor空间的一半,则年龄大于或等于该年龄的对象就可以直接进入老年代。

垃圾回收两种情况

MinorGC:新生代GC,指发生在新生代的内存回收,MinorGC发生频繁GC速度快FullGC: 老年代GC,又叫MajorGC,经常会伴随至少一次的MinorGc,FullGC的速度一般会比MinorGC速度慢10倍以上。

常见内存分配和垃圾回收参数:

-XX:+PrintGCDetails: 打印GC日志

-XX:PretenureSizeThreshold=3M:设置大对象直接进入老年代的值

-XX:MaxTenuringThreshold=1: 设置长期存活对象存活多少次转移到老年代,比如MinoGC回收一次依旧 存活则将对象转入老年代。

-XX:-HandlePromotionFailure:内存回收担保

垃圾回收器

在新生代工作的垃圾回收器:Serial, ParNew, ParallelScavenge 在老年代工作的垃圾回收器:CMS,Serial Old, Parallel Old 同时在新老生代工作的垃圾回收器:G1 -XX:+UseParNewGC : 使用ParNew 垃圾回收器

java -XX:+PrintCommandLineFlags -version

引用《深入理解Java虚拟机:JVM高级特性与最佳实践》的介绍:

所以,jdk8环境下,默认使用 Parallel Scavenge(新生代)+ Serial Old(老年代)

-XX:+PrintCommandLineFlagsjvm参数可查看默认设置收集器类型 -XX:+PrintGCDetails亦可通过打印的GC日志的新生代、老年代名称判断

堆内存对象回收

堆内存中没有被局部变量,静态变量,常量所引用得堆对象,会被垃圾回收线程回收

类加载过程

一个类得加载过程分别是 加载 验证 准备 解析 初始化 使用 卸载

加载: 将class对象加载到方法区 验证: 验证class对象是否符合jvm 规范 准备: 为类分配内存空间,给类变量分配内存空间,进行初始化(没有赋值), 解析: 符号引用替换为直接引用得过程 初始化: 堆类得静态变量进行赋值,实际意义的值

永久代(方法区)回收

方法区的回收条件比较苛刻 1.该类的所有实列已经被回收 2.该类的类加载器已经被回收 3.该类的字节码对象没有任何引用

GC ROOTS

方法局部变量,静态变量可以作为GCROOTS

JAVA对象的不同引用类型

1.强引用

Strutent student = new Student

. 软引用

// 强应用 public static Test test = new Test(); // 软应用 public static SoftReference<Test> softReference = new SoftReference<>(new Test()); // 虚引用 public static WeakReference<Test> weakReference = new WeakReference<>(new Test());

什么时候触发minorGC

1.新生代内存空间不够,老年代剩余空间大于新生代所有存活对象,可以触发minorGC 2.老年代剩余空间小于新生代所有存活对象,开启了内存分配担保,老年代剩余空间大于历代进入老年代对象得平均大小,此时可以触发minorGc

什么时候触发FULLGC

老年代内存可用大小小于新生代存活对象,且没有开启分配担保得情况下,触发fullgc老年代内存可用大小小于历代进入老年代对象得平均大小,触发fullgcminorGc后,survior内存空间不够,存活对象需要进入老年代后,老年代内存空间不足,需要触发fullgccms垃圾回收器,有一个参数限制了,如果达到了阈值也会进行回收

什么对象会进入老年代

达到存活年龄对象限制survior区放不下得存活对象可以直接进入老年代同龄对象超过了survivor空间50%的空间,会直接进入老年代
最新回复(0)